hdu 5267 pog loves szh IV(点分治+线段树)
2015-08-07 01:40
337 查看
好久之前写的题了。现在要重新开始写题解了。就从这题开始吧。
题意:一棵树,两点之间的权值为路径上的值异或得到,求任意两点之间的权值和,有修改操作,每次都要输出任意两点间的权值和。
做法:当时写这题写了好久。就说下一些关键的思路,因为细节部分真的是太多。首先不同的位独立考虑,然后任意两点我们肯定会想到点分治,点分治时会dfs求出子树里每个点到根节点的权值,然后进行配对求经过根节点的权值和。
那么这个题我们可以把分治的的过程给保存下来,因为修改一个点的权值就意味着在某一个点分治的阶段,那个点其下的点到根节点的权值全都异或1(因为按位不同考虑,假设那个位跟原来不一样)。所以可以弄出dfs序,然后区间更新即可。然后每一次分治的根节点我们要保存:其下1和0的个数,1和1配对的个数,0个0配对的个数,1和0配对的个数。那么在修改时,我们先把那颗子树上0和1对于这个根节点的贡献给消除,再去在子树上区间更新得到新的0和1的个数,再去重新计算根节点我要维护的那几个值。这样答案就可以重新知道了。
具体思路就是这样,但是比较繁琐,比如得维护每个点的每一次分治是属于哪个线段树,以及它在这个线段树中所能影响的范围(即他的子树dfs序的范围)。以及每次分治过程根节点的信息(就是刚才说的)。细节注意下就可以了。
PS:8.5k的代码也是写的很醉人。
AC代码:
题意:一棵树,两点之间的权值为路径上的值异或得到,求任意两点之间的权值和,有修改操作,每次都要输出任意两点间的权值和。
做法:当时写这题写了好久。就说下一些关键的思路,因为细节部分真的是太多。首先不同的位独立考虑,然后任意两点我们肯定会想到点分治,点分治时会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; }
相关文章推荐
- switf资源
- 编程软件一些配置问题
- CTimeSpan在VC6里是32位(4字节),在VC2013里是64位(8字节)
- switf资源
- 51cto培训课程
- 51cto培训课程
- Samba服务是基于企业级的文件共享和打印共享
- 51cto运维培训课程
- Unity Manual之Transform 变换
- 51cto运维培训课程
- Android Studio 1.3 正式发布
- HWOJ题目
- 按层次打印二叉树
- 2015 SWJTU ACM Summer Training Final Assessment 1st 部分题解
- Python: 在Unicode和普通字符串之间转换
- Python: 在Unicode和普通字符串之间转换
- SQL Server游标的使用【转】
- 有一段时间没写博客了,这段时间在忙公司项目,这周六若无加班准备开大
- chr()、unichr()和ord(),全半角转换,ValueError: unichr() arg not in range() (wide Python build)
- chr()、unichr()和ord(),全半角转换,ValueError: unichr() arg not in range() (wide Python build)