///****In the name of ALLAH, most Gracious, most Compassionate****//

#pragma GCC target ("avx2")
#pragma GCC optimization ("O3")
#pragma GCC optimization ("unroll-loops")

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef pair <int, int> pii;

#define ALL(a) a.begin(), a.end()
#define FastIO ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define IN freopen("input.txt","r+",stdin)
#define OUT freopen("output.txt","w+",stdout)

#define DBG(a) cerr<< "line "<<__LINE__ <<" : "<< #a <<" --> "<<(a)<<endl
#define NL cout<<endl

template < class T1,class T2>
ostream &operator <<(ostream &os,const pair < T1,T2 > &p)
{
    os<<"{"<<p.first<<","<<p.second<<"}";
    return os;
}

const int N=3e5+5;
const ll oo=1e9+7;

int p[N];


vector<int > child[N][2];


ll Tree[N];

void update(int idx, ll x,int n)
{
	// Let, n is the number of elements and our queries are
	// of the form query(n)-query(l-1), i.e range queries
	// Then, we should never put N or MAX in place of n here.
	while(idx<=n)
	{
		Tree[idx]= (Tree[idx] + x) % oo;
		idx+=(idx&-idx);
	}
}

ll query(int idx)
{
	ll sum=0;
	while(idx>0)
	{
		sum = (sum + Tree[idx]) % oo;
		idx-=(idx&-idx);
	}
	return sum;
}

ll root_to_node[N];
ll root_to_node_inv[N];

ll extended_euclidean(ll a, ll b, ll & x, ll & y) {
    if (a == 0) {
        x = 0;
        y = 1;
        return b;
    }
    ll x1, y1;
    ll d = extended_euclidean(b % a, a, x1, y1);
    x = y1 - (b / a) * x1;
    y = x1;
    return d;
}
ll mod_inverse(ll a,ll m)
{
    ll x, y;
    ll g = extended_euclidean(a, m, x, y);
    if (g != 1)
    {
        cout << "No solution!";
        return -1;
    }
    else
    {
        x = (x % m + m) % m;
        return x;
    }
}


int32_t main()
{
    FastIO;
    int h;
    cin>>h;
    int l = 1<<h-1;
    for(int i=1;i<=l;i++)
        cin>>p[i];
    for(int i=1;i<=l;i++)
    {

        int u = l +i -1;
        bool par = u % 2;
        int p = u/2;


        do
        {

            child[p][par].push_back(i);
            par = p % 2;
            p = p/2;
        }
        while(p);

    }

    root_to_node[0] =1;
    root_to_node_inv[0] =1;

    int total_node = (1<<h)-1;
    for(int i=1;i<=total_node;i++)
        root_to_node_inv[i] = mod_inverse(root_to_node[i] = (root_to_node[i/2] * i) % oo , oo);

    ll ans = 0;

    for(int lca=1;lca<l;lca++)
    {

        for(int leaf: child[lca][0])
        {
            ll g = root_to_node[l+ leaf-1] * root_to_node_inv[lca]% oo;
            g = (g * root_to_node[l+ p[leaf] - 1 ]) % oo;
            update(p[leaf] , g, l);
        }

        for(int leaf : child[lca][1])
        {
            ll g = root_to_node[l+leaf - 1] * root_to_node_inv[lca/2]% oo;
            int u = l + p[leaf] - 1;
            int par = u % 2;
            int  p = u/2;

            g = (g * u) % oo;
            g = (g * p) % oo;

            do
            {


                ll now = (query(child[p][!par].back()) - query(child[p][!par].front() - 1) )% oo;



                now  = now * root_to_node_inv[p] % oo;


                now = (now * g) %oo;

                ans = (ans + now) % oo;



                par  = p%2;
                p/=2;

                g= (g * p) %oo;
            }
            while(p);
        }


        for(int leaf: child[lca][0])
        {
            ll g = root_to_node[l+ leaf-1] * root_to_node_inv[lca] % oo;
            g = (g * root_to_node[l+ p[leaf] - 1 ]) % oo;
            update(p[leaf] , -g, l);
        }
    }

    ans = (ans  + oo) % oo;

    cout<<ans<<"\n";

}


Measured memory_bytes: 37816