hdu 5267 pog loves szh IV(点分治+线段树)

来源:互联网 发布:js 获取和设置cookie 编辑:程序博客网 时间:2024/06/05 00:38

好久之前写的题了。现在要重新开始写题解了。就从这题开始吧。

题意:一棵树,两点之间的权值为路径上的值异或得到,求任意两点之间的权值和,有修改操作,每次都要输出任意两点间的权值和。

做法:当时写这题写了好久。就说下一些关键的思路,因为细节部分真的是太多。首先不同的位独立考虑,然后任意两点我们肯定会想到点分治,点分治时会dfs求出子树里每个点到根节点的权值,然后进行配对求经过根节点的权值和。

那么这个题我们可以把分治的的过程给保存下来,因为修改一个点的权值就意味着在某一个点分治的阶段,那个点其下的点到根节点的权值全都异或1(因为按位不同考虑,假设那个位跟原来不一样)。所以可以弄出dfs序,然后区间更新即可。然后每一次分治的根节点我们要保存:其下1和0的个数,1和1配对的个数,0个0配对的个数,1和0配对的个数。那么在修改时,我们先把那颗子树上0和1对于这个根节点的贡献给消除,再去在子树上区间更新得到新的0和1的个数,再去重新计算根节点我要维护的那几个值。这样答案就可以重新知道了。

具体思路就是这样,但是比较繁琐,比如得维护每个点的每一次分治是属于哪个线段树,以及它在这个线段树中所能影响的范围(即他的子树dfs序的范围)。以及每次分治过程根节点的信息(就是刚才说的)。细节注意下就可以了。

PS:8.5k的代码也是写的很醉人。

AC代码:

#pragma comment(linker, "/STACK:102400000,102400000")#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<cstdlib>#include<stack>#include<queue>#include<set>#include<map>#include<cmath>#include<ctime>#include<string.h>#include<string>#include<sstream>#include<bitset>using namespace std;#define ll __int64#define ull unsigned __int64#define eps 1e-8#define NMAX 30000#define MOD 998244353//#define lson l,mid,rt<<1,d//#define rson mid+1,r,rt<<1|1,d#define PI acos(-1)template<class T>inline void scan_d(T &ret){    char c;    int flag = 0;    ret=0;    while(((c=getchar())<'0'||c>'9')&&c!='-');    if(c == '-')    {        flag = 1;        c = getchar();    }    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();    if(flag) ret = -ret;}const int maxn = 10000+10;struct Edge{    int v,next;}e[maxn*2];int head[maxn],ecnt;void add_edge(int u, int v){    e[ecnt].v = v;    e[ecnt].next = head[u];    head[u] = ecnt++;}int point;int Pos[maxn],Size[maxn];int dp[maxn],mi,pp,sz;struct Tree{    int zero,one,zz,oo,zo;}Tree[15][maxn];int ans[15];bool data[15][maxn],vis[maxn];void gao1(int u, int fa){    dp[u] = 1;    sz++;    for(int i = head[u]; ~i; i = e[i].next)    {        int v = e[i].v;        if(v == fa || vis[v]) continue;        gao1(v,u);        dp[u] += dp[v];    }}void gao2(int u, int fa){    int tmp = sz-dp[u];    for(int i = head[u]; ~i; i = e[i].next)    {        int v = e[i].v;        if(v == fa || vis[v]) continue;        gao2(v,u);        tmp = max(tmp,dp[v]);    }    if(tmp < mi)    {        mi = tmp;        pp = u;    }}int getbarycenter(int u){    sz = 0;    gao1(u,u);    mi = 1000000;    gao2(u,u);    return pp;}struct node{    int root, ge, l, r;    node(){}    node(int _root, int _ge, int _l, int _r):root(_root),ge(_ge),l(_l),r(_r) {}};vector<node>vec[maxn];bool a[15][maxn];void solve(int u, int fa, int w, int rt, int tou, int flag){    sz++;    a[flag][sz] = w;    int tmp = sz;    for(int i = head[u]; ~i; i = e[i].next)    {        int v = e[i].v;        if(v == fa || vis[v]) continue;        solve(v,u,w^data[flag][v],rt,tou,flag);    }    if(flag == 0) vec[u].push_back(node(rt,tou,tmp,sz));}int tot;int lson[maxn*30],rson[maxn*30];struct SegmentTree{    int zero,one;    bool flag;}T[15][maxn*30];int build(int l, int r){    int rt = ++tot;    for(int i = 0; i <= 14; i++)        T[i][rt].flag = 0;    if(l == r)    {//        T[rt].lson = T[rt].rson = 0;        for(int i = 0; i <= 14; i++)        {            T[i][rt].zero = T[i][rt].one = 0;            if(a[i][l] == 1) T[i][rt].one = 1;            else T[i][rt].zero = 1;        }        return rt;    }    int mid = (l+r)>>1;    lson[rt] = build(l,mid);    rson[rt] = build(mid+1,r);    for(int i = 0; i <= 14; i++)    {        T[i][rt].one = T[i][lson[rt]].one + T[i][rson[rt]].one;        T[i][rt].zero = T[i][lson[rt]].zero + T[i][rson[rt]].zero;    }    return rt;}void dfs(int u){    u = getbarycenter(u);//        cout<<"tree:"<<u<<" "<<sz<<endl;    if(sz == 1)    {        for(int i = 0; i <= 14; i++)            Tree[i][u].one = Tree[i][u].zero = Tree[i][u].oo = Tree[i][u].zz = Tree[i][u].zo = 0;//        vec[u].push_back(node(u,0,0,0));        return;    }    int z[15] = {0}, o[15] = {0}, oo[15] = {0}, zz[15] = {0}, zo[15] = {0};    for(int i = head[u]; ~i; i = e[i].next)    {        int v = e[i].v;        if(vis[v]) continue;        for(int j = 0; j <= 14; j++)        {            sz = 0;            solve(v,u,data[j][v],u,point,j);        }        int pos = build(1,sz);//        cout<<"shit1:"<<v<<" "<<sz<<" "<<T[0][pos].one<<endl;        Pos[point] = pos;        Size[point++] = sz;        for(int j = 0; j <= 14; j++)        {            oo[j] += T[j][pos].one*o[j];            zz[j] += T[j][pos].zero*z[j];            zo[j] += T[j][pos].one*z[j]+T[j][pos].zero*o[j];            o[j] += T[j][pos].one;            z[j] += T[j][pos].zero;        }    }    for(int i = 0; i <= 14; i++)    {        Tree[i][u].one = o[i];        Tree[i][u].zero = z[i];        Tree[i][u].oo = oo[i];        Tree[i][u].zz = zz[i];        Tree[i][u].zo = zo[i];        if(data[i][u] == 1) ans[i] += oo[i]+zz[i]+z[i];        else ans[i] += zo[i]+o[i];    }    vis[u] = 1;    for(int i = head[u]; ~i; i = e[i].next)    {        int v = e[i].v;        if(vis[v]) continue;        dfs(v);    }}void init(int n){    memset(ans,0,sizeof(ans));    memset(vis,0,sizeof(vis));    for(int i = 1; i <= n; i++)        vec[i].clear();}void pushdown(int rt, int flag){    if(T[flag][rt].flag)    {        swap(T[flag][lson[rt]].zero,T[flag][lson[rt]].one);        swap(T[flag][rson[rt]].zero,T[flag][rson[rt]].one);        T[flag][lson[rt]].flag ^= 1;        T[flag][rson[rt]].flag ^= 1;        T[flag][rt].flag = 0;    }}void update(int L, int R, int l, int r, int rt, int flag){    if(L <= l && R >= r)    {        T[flag][rt].flag ^= 1;        swap(T[flag][rt].zero,T[flag][rt].one);        return;    }    pushdown(rt,flag);    int mid = (l+r)>>1;    if(L <= mid) update(L,R,l,mid,lson[rt],flag);    if(R > mid) update(L,R,mid+1,r,rson[rt],flag);    T[flag][rt].one = T[flag][lson[rt]].one + T[flag][rson[rt]].one;    T[flag][rt].zero = T[flag][lson[rt]].zero + T[flag][rson[rt]].zero;}void rilegou(int x, int flag){    int num = vec[x].size();    for(int i = 0; i < num; i++)    {        int rt = vec[x][i].root,ge = vec[x][i].ge;        if(data[flag][rt] == 1) ans[flag] -= Tree[flag][rt].zero+Tree[flag][rt].oo+Tree[flag][rt].zz;        else ans[flag] -= Tree[flag][rt].one+Tree[flag][rt].zo;        int z = T[flag][Pos[ge]].zero, o = T[flag][Pos[ge]].one;        Tree[flag][rt].oo -= (Tree[flag][rt].one-o)*o;        Tree[flag][rt].zz -= (Tree[flag][rt].zero-z)*z;        Tree[flag][rt].zo -= (Tree[flag][rt].one-o)*z+(Tree[flag][rt].zero-z)*o;        Tree[flag][rt].one -= o;        Tree[flag][rt].zero -= z;        update(vec[x][i].l,vec[x][i].r,1,Size[ge],Pos[ge],flag);        z = T[flag][Pos[ge]].zero;        o = T[flag][Pos[ge]].one;        Tree[flag][rt].oo += o*Tree[flag][rt].one;        Tree[flag][rt].zz += z*Tree[flag][rt].zero;        Tree[flag][rt].zo += o*Tree[flag][rt].zero+z*Tree[flag][rt].one;        Tree[flag][rt].one += o;        Tree[flag][rt].zero += z;        if(data[flag][rt] == 1) ans[flag] += Tree[flag][rt].zero+Tree[flag][rt].oo+Tree[flag][rt].zz;        else ans[flag] += Tree[flag][rt].one+Tree[flag][rt].zo;    }    if(data[flag][x] == 1)    {        ans[flag] -= Tree[flag][x].zero+Tree[flag][x].oo+Tree[flag][x].zz;        ans[flag] += Tree[flag][x].one+Tree[flag][x].zo;        data[flag][x] = 0;    }    else    {        ans[flag] -= Tree[flag][x].one+Tree[flag][x].zo;        ans[flag] += Tree[flag][x].zero+Tree[flag][x].oo+Tree[flag][x].zz;        data[flag][x] = 1;    }}int main(){#ifdef GLQ    freopen("input.txt","r",stdin);//    freopen("o.txt","r",stdin);#endif    int n,q;    while(~scanf("%d%d",&n,&q))    {        memset(head,-1,sizeof(head));        ecnt = point = tot = 0;        init(n);        for(int i = 1; i <= n; i++)        {            int tmp;            scanf("%d",&tmp);            for(int j = 0; j <= 14; j++)                data[j][i] = !!(tmp&(1<<j));        }        for(int i = 1; i < n; i++)        {            int u,v;            scanf("%d%d",&u,&v);            add_edge(u,v);            add_edge(v,u);        }        dfs(1);//        cout<<vec[2].size()<<endl;        ll ret = 0;        for(int i = 0; i <= 14; i++)            ret += (ll)ans[i]*(1LL<<i);//        cout<<ret<<endl;        while(q--)        {            int x,y;            scanf("%d%d",&x,&y);            for(int i = 0; i <= 14; i++)            {                if(data[i][x] == !!(y&(1<<i))) continue;                ret -= (ll)ans[i]*(1LL<<i);                rilegou(x,i);                ret += (ll)ans[i]*(1LL<<i);            }            printf("%I64d\n",ret*2LL);        }    }    return 0;}



0 0