【集训第一天·特来卖萌】树链剖分之水水的例题
今天学习了树链剖分并且做了几道很有意思的题。。。
树链剖分的大致思想就是把一棵树转化成一条链(一个序列),然
后在上面做一些处理,例如:线段树。树转链的方法大致类似于 dfs
序,但是多了一个重边的处理。
上水题。(题名自行google)
1.BZOJ1036 ZJOJ2008 树的统计Count
标准模板题,超级水0.0。。。。。。
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<stack> 4 #include<queue> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #define inf 0x3f3f3f3f 10 #define ll long long 11 #define maxn 30005 12 #define lson u<<1,l,mid 13 #define rson u<<1|1,mid+1,r 14 using namespace std; 15 int w[maxn],head[maxn],tid[maxn],size[maxn],id[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],ecnt=1,cnt; 16 17 struct edge{ 18 int v,next; 19 }e[maxn*2]; 20 21 void adde(int u,int v){ 22 e[ecnt].v=v; 23 e[ecnt].next=head[u]; 24 head[u]=ecnt++; 25 } 26 27 void dfs1(int u,int pre){ 28 dep[u]=dep[pre]+1; 29 fa[u]=pre; 30 size[u]=1; 31 int msum=0; 32 for(int i=head[u];i;i=e[i].next){ 33 int v=e[i].v; 34 if(v==pre)continue; 35 dfs1(v,u); 36 size[u]+=size[v]; 37 if(size[v]>msum){ 38 msum=size[v]; 39 son[u]=v; 40 } 41 } 42 } 43 44 void dfs2(int u,int anc){ 45 tid[u]=++cnt; 46 top[u]=anc; 47 id[cnt]=u; 48 if(son[u])dfs2(son[u],anc); 49 for(int i=head[u];i;i=e[i].next){ 50 int v=e[i].v; 51 if(v==son[u]||v==fa[u])continue; 52 dfs2(v,v); 53 } 54 } 55 56 struct node{ 57 int l,r,ma,sum; 58 }t[4*maxn]; 59 60 void update(int u){ 61 t[u].sum=t[u<<1].sum+t[u<<1|1].sum; 62 t[u].ma=max(t[u<<1].ma,t[u<<1|1].ma); 63 } 64 65 void build(int u,int l,int r){ 66 t[u].l=l; 67 t[u].r=r; 68 if(l==r){ 69 t[u].sum=t[u].ma=w[id[l]]; 70 return; 71 } 72 int mid=(l+r)>>1; 73 build(lson); 74 build(rson); 75 update(u); 76 } 77 78 int askmax(int u,int l,int r){ 79 if(t[u].r==r&&t[u].l==l)return t[u].ma; 80 int mid=(t[u].l+t[u].r)>>1; 81 if(r<=mid)return askmax(u<<1,l,r); 82 if(l>mid)return askmax(u<<1|1,l,r); 83 else return max(askmax(u<<1,l,mid),askmax(u<<1|1,mid+1,r)); 84 } 85 86 int asksum(int u,int l,int r){ 87 if(t[u].r==r&&t[u].l==l)return t[u].sum; 88 int mid=(t[u].l+t[u].r)>>1; 89 if(r<=mid)return asksum(u<<1,l,r); 90 if(l>mid)return asksum(u<<1|1,l,r); 91 else return asksum(u<<1,l,mid)+asksum(u<<1|1,mid+1,r); 92 } 93 94 int findsum(int u,int v){ 95 int fu=top[u],fv=top[v]; 96 int tmp=0; 97 while(fu!=fv){ 98 if(dep[fu]<dep[fv]){ 99 swap(fu,fv); 100 swap(u,v); 101 } 102 tmp+=asksum(1,tid[fu],tid[u]); 103 u=fa[fu]; 104 fu=top[u]; 105 } 106 if(dep[u]>dep[v])swap(u,v); 107 return tmp+asksum(1,tid[u],tid[v]); 108 } 109 110 int findmax(int u,int v){ 111 int fu=top[u],fv=top[v]; 112 int tmp=-99999999; 113 while(fu!=fv){ 114 if(dep[fu]<dep[fv]){ 115 swap(fu,fv); 116 swap(u,v); 117 } 118 tmp=max(tmp,askmax(1,tid[fu],tid[u])); 119 u=fa[fu]; 120 fu=top[u]; 121 } 122 if(dep[u]>dep[v])swap(u,v); 123 return max(tmp,askmax(1,tid[u],tid[v])); 124 } 125 126 void change(int u,int k,int val){ 127 if(t[u].l==k&&t[u].r==k){ 128 t[u].ma=t[u].sum=val; 129 return; 130 } 131 int mid=(t[u].l+t[u].r)>>1; 132 if(k<=mid)change(u<<1,k,val); 133 else change(u<<1|1,k,val); 134 update(u); 135 } 136 137 int main(){ 138 int n,m; 139 scanf("%d",&n); 140 int a,b; 141 for(int i=1;i<n;i++)scanf("%d%d",&a,&b),adde(a,b),adde(b,a); 142 for(int i=1;i<=n;i++)scanf("%d",&w[i]),t[i].ma=-99999999; 143 dfs1(1,0); 144 dfs2(1,1); 145 build(1,1,n); 146 scanf("%d",&m); 147 for(int i=1;i<=m;i++){ 148 char s[100]; 149 scanf("%s",s); 150 scanf("%d%d",&a,&b); 151 if(s[0]=='C')change(1,tid[a],b); 152 else if(!strcmp(s,"QMAX"))printf("%d\n",findmax(a,b)); 153 else printf("%d\n",findsum(a,b)); 154 } 155 return 0; 156 }
2. BZOJ3626 LNOI2014 LCA
这东西非常扯淡,题解和题名完全不是一个等级的东西(⊙o⊙)
这里简单地说说思路 更多细节参考 http://www.cnblogs.com/Paul-Guderian/p/6628570.html
①利用铺路的思想,把题目所给的每个区间中的点都一步步走回根节点,路上经过的节点点权+1。再考虑 Z(题目要求查询的节点),从Z节点向根走,把路上经过的所有节点的权值加起来,即为所求。
②我们求的时 [l,r]区间内的点和Z的lca的深度和,即[l,r](z)
那么可用前缀思想把它转化为[1,r](z)-[1,l-1](z)
把输入的区间存入一个结构体数组(l存一个,r再存一个,l的结构体存符号"-",r存"+"),排序。
当走到端点值时进行操作,给所对应的询问标号加上或减去具体的答案。
PS:通过此方法可以省时间并且符合节点遍历顺序,具体操作见代码
CODE:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define ll long long 7 #define inf 1000000000 8 #define mod 201314 9 using namespace std; 10 inline ll read() 11 { 12 ll x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 int n,m,cnt,place; 18 int bin[20]; 19 int son[50005],last[50005],fa[50005],belong[50005],pl[50005],deep[50005]; 20 struct edge{int to,next;}e[50005]; 21 struct que{int z,ans1,ans2;}q[50005]; 22 struct data{int num,p;bool flag;}a[100005]; 23 struct seg{int l,r,sum,tag,size;}t[200005]; 24 inline bool operator<(data a,data b) 25 { 26 return a.p<b.p; 27 } 28 inline void insert(int u,int v) 29 { 30 e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt; 31 } 32 void dfs1(int x) 33 { 34 son[x]=1; 35 for(int i=last[x];i;i=e[i].next) 36 { 37 if(e[i].to==fa[x])continue; 38 deep[e[i].to]=deep[x]+1; 39 fa[e[i].to]=x; 40 dfs1(e[i].to); 41 son[x]+=son[e[i].to]; 42 } 43 } 44 void dfs2(int x,int chain) 45 { 46 belong[x]=chain;pl[x]=++place; 47 int k=n; 48 for(int i=last[x];i;i=e[i].next) 49 if(e[i].to!=fa[x]&&son[e[i].to]>son[k]) 50 k=e[i].to; 51 if(k!=n)dfs2(k,chain); 52 for(int i=last[x];i;i=e[i].next) 53 if(e[i].to!=fa[x]&&e[i].to!=k) 54 dfs2(e[i].to,e[i].to); 55 } 56 inline void pushdown(int k) 57 { 58 if(t[k].l==t[k].r||!t[k].tag)return; 59 int tag=t[k].tag;t[k].tag=0; 60 t[k<<1].sum=t[k<<1].sum+t[k<<1].size*tag; 61 t[k<<1|1].sum=t[k<<1|1].sum+t[k<<1|1].size*tag; 62 t[k<<1].tag=t[k<<1].tag+tag; 63 t[k<<1|1].tag=t[k<<1|1].tag+tag; 64 } 65 void build(int k,int l,int r) 66 { 67 t[k].l=l;t[k].r=r;t[k].size=r-l+1; 68 if(l==r)return; 69 int mid=(l+r)>>1; 70 build(k<<1,l,mid); 71 build(k<<1|1,mid+1,r); 72 } 73 void update(int k,int x,int y) 74 { 75 pushdown(k); 76 int l=t[k].l,r=t[k].r; 77 if(l==x&&y==r) 78 { 79 t[k].tag++;t[k].sum+=t[k].size; 80 return; 81 } 82 int mid=(l+r)>>1; 83 if(y<=mid)update(k<<1,x,y); 84 else if(x>mid)update(k<<1|1,x,y); 85 else 86 { 87 update(k<<1,x,mid); 88 update(k<<1|1,mid+1,y); 89 } 90 t[k].sum=t[k<<1].sum+t[k<<1|1].sum; 91 } 92 void solve_update(int x,int f) 93 { 94 while(belong[x]!=belong[f]) 95 { 96 update(1,pl[belong[x]],pl[x]); 97 x=fa[belong[x]]; 98 } 99 update(1,pl[f],pl[x]); 100 } 101 int query(int k,int x,int y) 102 { 103 pushdown(k); 104 int l=t[k].l,r=t[k].r; 105 if(l==x&&y==r)return t[k].sum; 106 int mid=(l+r)>>1; 107 if(y<=mid)return query(k<<1,x,y); 108 else if(x>mid)return query(k<<1|1,x,y); 109 else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y); 110 } 111 int solve_query(int x,int f) 112 { 113 int sum=0; 114 while(belong[x]!=belong[f]) 115 { 116 sum+=query(1,pl[belong[x]],pl[x]); 117 sum%=mod; 118 x=fa[belong[x]]; 119 } 120 sum+=query(1,pl[f],pl[x]);sum%=mod; 121 return sum; 122 } 123 int main() 124 { 125 //freopen("lca.in","r",stdin); 126 //freopen("lca.out","w",stdout); 127 bin[0]=1;for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1); 128 n=read();m=read(); 129 for(int i=1;i<n;i++) 130 { 131 int x=read();insert(x,i); 132 } 133 int tot=0; 134 for(int i=1;i<=m;i++) 135 { 136 int l=read(),r=read(); 137 q[i].z=read(); 138 a[++tot].p=l-1;a[tot].num=i;a[tot].flag=0; 139 a[++tot].p=r;a[tot].num=i;a[tot].flag=1; 140 } 141 build(1,1,n); 142 sort(a+1,a+tot+1); 143 dfs1(0);dfs2(0,0); 144 int now=-1; 145 for(int i=1;i<=tot;i++) 146 { 147 while(now<a[i].p) 148 { 149 now++; 150 solve_update(now,0); 151 } 152 int t=a[i].num; 153 if(!a[i].flag)q[t].ans1=solve_query(q[t].z,0); 154 else q[t].ans2=solve_query(q[t].z,0); 155 } 156 for(int i=1;i<=m;i++) 157 printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod); 158 return 0; 159 }
3.NOIP2015运输计划
这个题很有意思 二分答案+树链剖分+差分数组
大致思路:
首先预处理出每个货物送达的初始距离,用lca(tarjan,倍增,暴力,树链剖分--方法自便)+dis数组求出。sort一遍,把距离大的放在数组后面。二分最大时间最小值,找出大于这个时间的货物然后让这些货物铺路,找出这些货物共同经过的某些路(称为共路),遍历共路,找出最长共路。若 二分的答案+此共路的长度>=最大货物运输距离,则check通过。
另外,这个题也使用了上题铺路的思想,只不过使用差分实现的。
的用树链剖分把这棵树映射到一条链上利用差分,每个货物进一条链时,在链的首部给通货量+1,出去时在出去的节点-1。
PS:注意此题给的是边权,可通过下放给儿子节点的方式来转化为点权,且差分时注意 脚标+1,详见代码。
CODE:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #define ll long long 7 #define inf 1000000000 8 #define mod 201314 9 using namespace std; 10 inline ll read() 11 { 12 ll x=0,f=1;char ch=getchar(); 13 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 14 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 15 return x*f; 16 } 17 int n,m,cnt,place; 18 int bin[20]; 19 int son[50005],last[50005],fa[50005],belong[50005],pl[50005],deep[50005]; 20 struct edge{int to,next;}e[50005]; 21 struct que{int z,ans1,ans2;}q[50005]; 22 struct data{int num,p;bool flag;}a[100005]; 23 struct seg{int l,r,sum,tag,size;}t[200005]; 24 inline bool operator<(data a,data b){ 25 return a.p<b.p; 26 } 27 inline void insert(int u,int v){ 28 e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt; 29 } 30 void dfs1(int x){ 31 son[x]=1; 32 for(int i=last[x];i;i=e[i].next){ 33 if(e[i].to==fa[x])continue; 34 deep[e[i].to]=deep[x]+1; 35 fa[e[i].to]=x; 36 dfs1(e[i].to); 37 son[x]+=son[e[i].to]; 38 } 39 } 40 void dfs2(int x,int chain){ 41 belong[x]=chain;pl[x]=++place; 42 int k=n; 43 for(int i=last[x];i;i=e[i].next) 44 if(e[i].to!=fa[x]&&son[e[i].to]>son[k]) 45 k=e[i].to; 46 if(k!=n)dfs2(k,chain); 47 for(int i=last[x];i;i=e[i].next) 48 if(e[i].to!=fa[x]&&e[i].to!=k) 49 dfs2(e[i].to,e[i].to); 50 } 51 inline void pushdown(int k){ 52 if(t[k].l==t[k].r||!t[k].tag)return; 53 int tag=t[k].tag;t[k].tag=0; 54 t[k<<1].sum=t[k<<1].sum+t[k<<1].size*tag; 55 t[k<<1|1].sum=t[k<<1|1].sum+t[k<<1|1].size*tag; 56 t[k<<1].tag=t[k<<1].tag+tag; 57 t[k<<1|1].tag=t[k<<1|1].tag+tag; 58 } 59 void build(int k,int l,int r){ 60 t[k].l=l;t[k].r=r;t[k].size=r-l+1; 61 if(l==r)return; 62 int mid=(l+r)>>1; 63 build(k<<1,l,mid); 64 build(k<<1|1,mid+1,r); 65 } 66 void update(int k,int x,int y){ 67 pushdown(k); 68 int l=t[k].l,r=t[k].r; 69 if(l==x&&y==r) 70 { 71 t[k].tag++;t[k].sum+=t[k].size; 72 return; 73 } 74 int mid=(l+r)>>1; 75 if(y<=mid)update(k<<1,x,y); 76 else if(x>mid)update(k<<1|1,x,y); 77 else { 78 update(k<<1,x,mid); 79 update(k<<1|1,mid+1,y); 80 } 81 t[k].sum=t[k<<1].sum+t[k<<1|1].sum; 82 } 83 void solve_update(int x,int f){ 84 while(belong[x]!=belong[f]){ 85 update(1,pl[belong[x]],pl[x]); 86 x=fa[belong[x]]; 87 } 88 update(1,pl[f],pl[x]); 89 } 90 int query(int k,int x,int y){ 91 pushdown(k); 92 int l=t[k].l,r=t[k].r; 93 if(l==x&&y==r)return t[k].sum; 94 int mid=(l+r)>>1; 95 if(y<=mid)return query(k<<1,x,y); 96 else if(x>mid)return query(k<<1|1,x,y); 97 else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y); 98 } 99 int solve_query(int x,int f) 100 { 101 int sum=0; 102 while(belong[x]!=belong[f]) 103 { 104 sum+=query(1,pl[belong[x]],pl[x]); 105 sum%=mod; 106 x=fa[belong[x]]; 107 } 108 sum+=query(1,pl[f],pl[x]);sum%=mod; 109 return sum; 110 } 111 int main() 112 { 113 bin[0]=1;for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1); 114 n=read();m=read(); 115 for(int i=1;i<n;i++) 116 { 117 int x=read();insert(x,i); 118 } 119 int tot=0; 120 for(int i=1;i<=m;i++) 121 { 122 int l=read(),r=read(); 123 q[i].z=read(); 124 a[++tot].p=l-1;a[tot].num=i;a[tot].flag=0; 125 a[++tot].p=r;a[tot].num=i;a[tot].flag=1; 126 } 127 build(1,1,n); 128 sort(a+1,a+tot+1); 129 dfs1(0);dfs2(0,0); 130 int now=-1; 131 for(int i=1;i<=tot;i++) 132 { 133 while(now<a[i].p) 134 { 135 now++; 136 solve_update(now,0); 137 } 138 int t=a[i].num; 139 if(!a[i].flag)q[t].ans1=solve_query(q[t].z,0); 140 else q[t].ans2=solve_query(q[t].z,0); 141 } 142 for(int i=1;i<=m;i++) 143 printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod); 144 return 0; 145 }
4.BZOJ2243 SDOI2011 染色
大致就是树链剖分+线段树(染色合并,01串覆盖的升级),非常之水,上代码。
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<stack> 4 #include<queue> 5 #include<cstring> 6 #include<algorithm> 7 #include<vector> 8 #include<cmath> 9 #define inf 0x3f3f3f3f 10 #define ll long long 11 #define maxn 300005 12 #define lson u<<1,l,mid 13 #define rson u<<1|1,mid+1,r 14 using namespace std; 15 int top[maxn],fa[maxn],tid[maxn],dep[maxn],val[maxn],dis[maxn],head[maxn],q[maxn],cov[maxn],pre[maxn],son[maxn],www[maxn],size[maxn],n,m,k=1,tot; 16 struct edge{ 17 int v,next,w; 18 }e[2*maxn]; 19 20 struct post{ 21 int len,a,b; 22 }p[maxn]; 23 void adde(int u,int v,int w){ 24 e[k].v=v; 25 e[k].w=w; 26 e[k].next=head[u]; 27 head[u]=k++; 28 } 29 30 bool cmp(post a,post b){ 31 return a.len<b.len; 32 } 33 void dfs1(int u,int pre,int Dis){ 34 size[u]=1; 35 dep[u]=dep[pre]+1; 36 dis[u]=Dis; 37 fa[u]=pre; 38 int smax=0; 39 for(int i=head[u];i;i=e[i].next){ 40 int v=e[i].v; 41 if(v==pre)continue; 42 www[v]=e[i].w; 43 dfs1(v,u,Dis+e[i].w); 44 size[u]+=size[v]; 45 if(size[v]>smax){ 46 smax=size[v]; 47 son[u]=v; 48 } 49 } 50 } 51 52 void dfs2(int u,int tt){ 53 tid[u]=++tot; 54 top[u]=tt; 55 val[tot]=www[u]; 56 if(son[u])dfs2(son[u],tt); 57 for(int i=head[u];i;i=e[i].next){ 58 int v=e[i].v; 59 if(v==fa[u]||v==son[u])continue; 60 dfs2(v,v); 61 } 62 } 63 64 int lca(int a,int b){ 65 int ta=top[a],tb=top[b]; 66 while(ta!=tb){ 67 if(dep[ta]<dep[tb]){ 68 swap(ta,tb); 69 swap(a,b); 70 } 71 a=fa[ta]; 72 ta=top[a]; 73 } 74 if(dep[a]<dep[b])return a; 75 return b; 76 } 77 78 void pave(int u,int v){ 79 int tu=top[u],tv=top[v]; 80 while(tu!=tv){ 81 if(dep[tu]<dep[tv]){ 82 swap(u,v);swap(tu,tv); 83 } 84 cov[tid[tu]]++;cov[tid[u]+1]--; 85 u=fa[tu]; 86 tu=top[u]; 87 } 88 if(dep[u]>dep[v])swap(u,v); 89 cov[tid[u]+1]++; 90 cov[tid[v]+1]--; 91 } 92 bool check(int x){ 93 int sd,all=0,fail; 94 for(int i=1;i<=m;i++){if(p[i].len>x){sd=i;fail=m-i+1;break;}} 95 if(q[fail])return q[fail]+x>=p[m].len; 96 for(int i=1;i<=tot;i++)cov[i]=0; 97 for(int i=sd;i<=m;i++)pave(p[i].a,p[i].b); 98 for(int i=1;i<=tot;i++){ 99 all+=cov[i]; 100 if(all==fail)q[fail]=max(q[fail],val[i]); 101 } 102 return q[fail]+x>=p[m].len; 103 } 104 int main(){ 105 scanf("%d%d",&n,&m); 106 int big=0; 107 for(int i=1;i<n;i++){ 108 int a,b,c; 109 scanf("%d%d%d",&a,&b,&c); 110 adde(a,b,c); 111 adde(b,a,c); 112 } 113 dfs1(1,0,0); 114 dfs2(1,1); 115 for(int i=1;i<=m;i++){ 116 int a,b; 117 scanf("%d%d",&a,&b); 118 p[i].a=a;p[i].b=b; 119 p[i].len=dis[a]+dis[b]-2*dis[(lca(a,b))]; 120 big=max(big,p[i].len); 121 }sort(p+1,p+1+m,cmp); 122 int l=0,r=big; 123 while(l<r){ 124 int mid=(l+r)>>1; 125 if(check(mid))r=mid; 126 else l=mid+1; 127 } 128 printf("%d",r); 129 return 0; 130 }
5.BZOJ2819 Nim
妈蛋。。还搞上了博弈论,,于是 y水j老师花20min讲完了博弈论。。桑心0.0
大致思路:
树链剖分+线段树/树状数组+博弈论
其实只要你懂博弈论这个题还是非常简单的(博弈论自己网上学),使用XOR可轻松搞定,每堆石子的个数为x,它的sg值也为x,直接^就行,是不是炒鸡简单?
至于树链剖分,其实是快速查找路径(u->v),用一个线段树直接搞出每个区间的XOR值就行了23333此题就如此地水过了。
还有就是,由于只涉及到单点修改和区间查询 ,聪明的召唤师可直接使用lowbit树状数组,秀了我一脸,懵逼ing……
PS:不要以为之输入 Q和C 你就可以用scanf读入单个字符判断操作
老夫就是被这个东西祸害了好久
原因:你读入数字后还有一个回车 char c;scanf("%c",&c)后会读入一个空格,然而水水的样例还是过,这就有点坑人
处理方法
一:读入字符串 (scanf读入字符串会自动省略 "空格"和"回车")
二:scanf(" %c",&c) %c前的空格千万不能省去否则就会读入 "回车" 导致程序错误
CODE:
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<queue> 7 #define lson u<<1,l,mid 8 #define rson u<<1|1,mid+1,r 9 #define N 500005 10 using namespace std; 11 int val[N],id[N],top[N],tid[N],dep[N],siz[N],fa[N],son[N],head[N],n,m,k=1,tot; 12 struct edge{int v,next;}e[2*N]; 13 struct tree{int l,r,sum;}t[4*N]; 14 int read(){ 15 char c;int x=0;c=getchar(); 16 while(c>'9'||c<'0')c=getchar(); 17 while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar(); 18 return x; 19 } 20 21 void adde(int u,int v){ 22 e[k].v=v; 23 e[k].next=head[u]; 24 head[u]=k++; 25 } 26 27 28 void dfs1(int u,int pre){ 29 siz[u]=1; 30 fa[u]=pre; 31 dep[u]=dep[pre]+1; 32 for(int i=head[u];i;i=e[i].next){ 33 int v=e[i].v; 34 if(v==pre)continue; 35 dfs1(v,u); 36 siz[u]+=siz[v]; 37 if(siz[v]>siz[son[u]])son[u]=v; 38 } 39 } 40 41 void dfs2(int u,int tt){ 42 tid[u]=++tot; 43 top[u]=tt; 44 id[tot]=u; 45 if(son[u])dfs2(son[u],tt); 46 for(int i=head[u];i;i=e[i].next){ 47 int v=e[i].v; 48 if(v==fa[u]||v==son[u])continue; 49 dfs2(v,v); 50 } 51 } 52 53 void pushup(int u){ 54 t[u].sum=t[u<<1].sum^t[u<<1|1].sum; 55 } 56 57 void build(int u,int l,int r){ 58 t[u].l=l; 59 t[u].r=r; 60 if(l==r){ 61 t[u].sum=val[id[l]]; 62 return; 63 } 64 int mid=(l+r)>>1; 65 build(lson); 66 build(rson); 67 pushup(u); 68 } 69 70 void update(int u,int pos,int ch){ 71 if(t[u].l==t[u].r){ 72 t[u].sum=ch; 73 return; 74 } 75 int mid=(t[u].l+t[u].r)>>1; 76 if(pos<=mid)update(u<<1,pos,ch); 77 else update(u<<1|1,pos,ch); 78 pushup(u); 79 } 80 81 int query(int u,int l,int r){ 82 if(t[u].l==l&&t[u].r==r)return t[u].sum; 83 int mid=(t[u].l+t[u].r)>>1; 84 if(r<=mid)return query(u<<1,l,r); 85 if(l>mid)return query(u<<1|1,l,r); 86 return query(u<<1,l,mid)^query(u<<1|1,mid+1,r); 87 } 88 89 bool fuck(int u,int v){ 90 int ans=0; 91 while(top[u]!=top[v]){ 92 if(dep[top[u]]<dep[top[v]])swap(u,v); 93 ans^=query(1,tid[top[u]],tid[u]); 94 u=fa[top[u]]; 95 } 96 if(u==v)return ans^val[u]; 97 if(dep[u]>dep[v])swap(u,v); 98 ans^=query(1,tid[u],tid[v]); 99 return ans; 100 } 101 102 int main(){ 103 n=read(); 104 for(int i=1;i<=n;i++)val[i]=read();int a,b; 105 for(int i=1;i<n;i++)a=read(),b=read(),adde(a,b),adde(b,a); 106 dfs1(1,0);dfs2(1,1);build(1,1,tot);m=read(); 107 for(int i=1;i<=m;i++){ 108 char s[3]; 109 scanf("%s",&s); 110 a=read();b=read(); 111 if(s[0]=='Q')fuck(a,b)?puts("Yes"):puts("No"); 112 else val[a]=b,update(1,tid[a],b); 113 } 114 return 0; 115 }
6.BZOJ4034 HAOI2015 树上操作
这个题非常之水,我都懒得写它,吐槽一下,作为省选怎能这样??
首先是树链剖分可以做,加一个dfs序(或用size数组表示儿子节点总数,对应到链上表示子树)来修改自己的子树。
听可爱的lg鸡小盆友说此题甚至可以不用树链剖分,直接dfs序+线段树。。
代码网上直接抄的,看不看无所谓。
CODE:
1 Description 2 有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个 3 操作,分为三种: 4 操作 1 :把某个节点 x 的点权增加 a 。 5 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。 6 操作 3 :询问某个节点 x 到根的路径中所有点的点权和。 7 Input 8 第一行包含两个整数 N, M 。表示点数和操作数。 9 接下来一行 N 个整数,表示树中节点的初始权值。 10 接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。 11 再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操 12 作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。 13 Output 14 对于每个询问操作,输出该询问的答案。答案之间用换行隔开。 15 Sample Input 16 5 5 17 18 1 2 3 4 5 19 20 1 2 21 22 1 4 23 24 2 3 25 26 2 5 27 28 3 3 29 30 1 2 1 31 32 3 5 33 34 2 1 2 35 36 3 3 37 Sample Output 38 6 39 40 9 41 42 13 43 44 HINT 45 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不 46 47 会超过 10^6 。 48 题解:树链剖分裸题,支持点修改,链查询,子树修改,子树查询。 49 [html] view plain copy 在CODE上查看代码片派生到我的代码片 50 #include<iostream> 51 #include<cstdio> 52 #include<cstring> 53 #include<algorithm> 54 using namespace std; 55 const int N=100100; 56 int point[N],next[N*4],belong[N],siz[N],son[N],pos[N],deep[N]; 57 int n,m,tot=1,num=0,fa[N]; 58 long long tr[N*4],de[N*4],r[N]; 59 bool use[N]; 60 struct S{ 61 int st,en; 62 }aa[N*4]; 63 inline void add(int x,int y) 64 { 65 tot+=1;next[tot]=point[x];point[x]=tot; 66 aa[tot].st=x;aa[tot].en=y; 67 tot+=1;next[tot]=point[y];point[y]=tot; 68 aa[tot].st=y;aa[tot].en=x; 69 } 70 inline void dfs_1(int x) 71 { 72 int i; 73 siz[x]=1; 74 use[x]=false; 75 for(i=point[x];i;i=next[i]) 76 if(use[aa[i].en]){ 77 deep[aa[i].en]=deep[x]+1; 78 fa[aa[i].en]=x; 79 dfs_1(aa[i].en); 80 siz[x]+=siz[aa[i].en]; 81 } 82 } 83 inline void dfs_2(int x,int y) 84 { 85 int i,k=0; 86 num+=1; 87 pos[x]=son[x]=num; 88 belong[x]=y; 89 for(i=point[x];i;i=next[i]) 90 if(deep[x]<deep[aa[i].en]&&siz[k]<siz[aa[i].en]) 91 k=aa[i].en; 92 if(k==0) return ; 93 dfs_2(k,y);son[x]=max(son[k],son[x]); 94 for(i=point[x];i;i=next[i]) 95 if(deep[x]<deep[aa[i].en]&&k!=aa[i].en){ 96 dfs_2(aa[i].en,aa[i].en); 97 son[x]=max(son[x],son[aa[i].en]); 98 } 99 } 100 #define mid (l+r)/2 101 #define L k<<1,l,mid 102 #define R k<<1|1,mid+1,r 103 inline void paint(int k,int l,int r,long long z) 104 { 105 de[k]+=z; 106 tr[k]+=(r-l+1)*z; 107 } 108 inline void pushdown(int k,int l,int r) 109 { 110 if(l==r) return ; 111 paint(L,de[k]); 112 paint(R,de[k]); 113 de[k]=0; 114 } 115 inline void insert(int k,int l,int r,int x,long long y) 116 { 117 if(l==r&&l==x){ 118 tr[k]+=y; 119 return ; 120 } 121 pushdown(k,l,r); 122 if(x<=mid) insert(L,x,y); 123 else insert(R,x,y); 124 tr[k]=tr[k<<1]+tr[k<<1|1]; 125 } 126 inline void change(int k,int l,int r,int x,int y,long long z) 127 { 128 if(x<=l&&y>=r){ 129 paint(k,l,r,z); 130 return ; 131 } 132 pushdown(k,l,r); 133 if(x<=mid) change(L,x,y,z); 134 if(y>mid) change(R,x,y,z); 135 tr[k]=tr[k<<1]+tr[k<<1|1]; 136 } 137 inline long long qurey(int k,int l,int r,int x,int y) 138 { 139 long long sum=0; 140 if(x<=l&&y>=r) return tr[k]; 141 pushdown(k,l,r); 142 if(x<=mid) sum+=qurey(L,x,y); 143 if(y>mid) sum+=qurey(R,x,y); 144 return sum; 145 } 146 inline long long ask(int x,int y) 147 { 148 long long sum=0; 149 while(belong[x]!=belong[y]){ 150 sum+=qurey(1,1,n,pos[belong[x]],pos[x]); 151 x=fa[belong[x]]; 152 } 153 sum+=qurey(1,1,n,pos[y],pos[x]); 154 return sum; 155 } 156 int main() 157 { 158 int i,j,x,t,root; 159 long long y; 160 memset(use,1,sizeof(use)); 161 scanf("%d%d",&n,&m); 162 for(i=1;i<=n;++i) scanf("%lld",&r[i]); 163 for(i=1;i<n;++i){ 164 scanf("%d%d",&x,&y); 165 add(x,y); 166 } 167 dfs_1(1); 168 dfs_2(1,1); 169 for(i=1;i<=n;++i){ 170 insert(1,1,n,pos[i],r[i]); 171 if(deep[i]==0) root=i; 172 } 173 while(m--){ 174 scanf("%d",&t); 175 if(t==1||t==2){ 176 scanf("%d%lld",&x,&y); 177 if(t==1) insert(1,1,n,pos[x],y); 178 if(t==2) change(1,1,n,pos[x],son[x],y); 179 } 180 else{ 181 scanf("%d",&x); 182 printf("%lld\n",ask(x,root)); 183 } 184 } 185 }
至此,愉快的一天就结束了。很累很充实哈!
哈哈哈哈即使是停掉常规课学竞赛老子依然写完了生物和英语作业,屌否?
现在是22:20,可爱的lg鸡,美腻的张姐,和猥琐的lence_鸡正在CS:GO
勤奋的二哥仍然在学习KMP
我花了一个小时写完了这个博客,快哉快哉。。。
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。