CC DGCD:Dynamic GCD——題解
阿新 • • 發佈:2017-11-25
++ query ble lan color *** cst main 沒有
https://vjudge.net/problem/CodeChef-DGCD
https://www.codechef.com/problems/DGCD
題目大意:
給一顆帶點權的樹,兩個操作:
1.將兩點間最短路上的點權+d
2.查詢兩點間最短路上的點權的GCD
顯然又是樹鏈剖分,點這裏看樹鏈剖分原理。
但是我們發現一個問題,我們雖然可以建立線段樹維護GCD,但是沒有辦法處理區間修改問題。
我們考慮更相減損之術的原理,兩數做差後的結果和小數的GCD=原來的GCD。
所以我們在維護單點權值的同時維護相鄰點權的差值,則GCD(區間內所有相鄰點權差的GCD,區間首位點權)就是我們要查的值。
雖然這麽說很簡單,但是有很多具體細節,大體比較難解決的比如:
1.修改區間的時候,單點權值要用lazy標記維護,而相鄰點權的差值就單點修改兩次(註意:有些情況下也可能只有一次)即可。
2.詢問的時候,單點權值單點查詢即可,相鄰點權的差值區間查詢,註意區間長度為點數-1,也就是說我們可能會碰到空區間,特判掉。
其余具體操作請看代碼。
#include<cstdio> #include<iostream> using namespace std; const int N=50001; const int INF=2147483647; /*============================** *************基本操作************ **============================*/ inline int read(){ int X=0,w=0;char ch=0; while(ch<‘0‘||ch>‘9‘){w|=ch==‘-‘;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘)X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct node{ int to; int nxt; }edge[2*N]; struct tree{ int lazy;int d; int v; }t[4*N]; int head[N],cnt=0,n; inline void add(int u,int v){ cnt++; edge[cnt].to=v; edge[cnt].nxt=head[u]; head[u]=cnt; return; } inline int abs(int x){ return x>0?x:-x; } int gcd(int x,int y){ return y?gcd(y,x%y):abs(x); } int fa[N],dep[N],size[N],son[N],top[N],pos[N],idx[N]; int val[N]; /*============================** *************樹鏈剖分************ **============================*/ void dfs1(int u){ size[u]=1; for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa[u])continue; fa[v]=u;dep[v]=dep[u]+1; dfs1(v);
size[u]+=size[v]; if(!son[u]||size[v]>size[son[u]])son[u]=v; } return; } int tot; void dfs2(int u,int anc){ tot++; pos[u]=tot; idx[tot]=u; top[u]=anc; if(!son[u])return; dfs2(son[u],anc); for(int i=head[u];i;i=edge[i].nxt){ int v=edge[i].to; if(v==fa[u]||v==son[u])continue; dfs2(v,v); } return; } inline void init(){ dfs1(1); top[1]=idx[1]=pos[1]=1; tot=1; dfs2(1,1); return; } /*============================** ************傳遞lazy************ **============================*/ inline void pushdown(int a,bool is_leaf){ if(is_leaf){ t[a].v+=t[a].lazy; }else{ t[a*2].lazy+=t[a].lazy; t[a*2+1].lazy+=t[a].lazy; } t[a].lazy=0; return; } /*============================** *************建樹操作************ **============================*/ void build(int a,int l,int r){ if(l==r){ t[a].v=val[idx[l]]; t[a].d=val[idx[l]]-val[idx[l-1]]; return; } int mid=(l+r)>>1; build(a*2,l,mid); build(a*2+1,mid+1,r); t[a].d=gcd(t[a*2].d,t[a*2+1].d); return; } /*============================** *************查詢操作************ **============================*/ int point_query(int a,int l,int r,int k){ pushdown(a,(l==r)); if(l==r){ return t[a].v; } int mid=(l+r)>>1; if(k<=mid)return point_query(a*2,l,mid,k); return point_query(a*2+1,mid+1,r,k); } int range_query(int a,int l,int r,int l1,int r1){ if(l1>r1)return 0; if(r<l1||r1<l)return 0; if(l1<=l&&r<=r1){ return t[a].d; } int mid=(l+r)>>1; return gcd(range_query(a*2,l,mid,l1,r1),range_query(a*2+1,mid+1,r,l1,r1)); } int path_query(int u,int v){ if(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;} if(top[u]!=u) return gcd(path_query(fa[top[u]],v),gcd(range_query(1,1,n,pos[son[top[u]]],pos[u]),point_query(1,1,n,pos[top[u]]))); return gcd(path_query(fa[top[u]],v),point_query(1,1,n,pos[top[u]])); } if(dep[u]>dep[v]){int t=u;u=v;v=t;} if(u!=v) return gcd(point_query(1,1,n,pos[u]),range_query(1,1,n,pos[son[u]],pos[v])); return point_query(1,1,n,pos[u]); } /*============================** *************修改操作************ **===========================**/ void point_modi(int a,int l,int r,int k,int c){ if(l==r){ t[a].d+=c; return; } int mid=(l+r)>>1; if(k<=mid)point_modi(a*2,l,mid,k,c); else point_modi(a*2+1,mid+1,r,k,c); t[a].d=gcd(t[a*2].d,t[a*2+1].d); return; } void range_modi(int a,int l,int r,int l1,int r1,int v){ if(r1<l||r<l1)return; pushdown(a,(l==r)); if(l1<=l&&r<=r1){ t[a].lazy+=v; return; } int mid=(l+r)>>1; range_modi(a*2,l,mid,l1,r1,v); range_modi(a*2+1,mid+1,r,l1,r1,v); return; } void path_modi(int u,int v,int c){ if(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]){int t=u;u=v;v=t;} point_modi(1,1,n,pos[top[u]],c); if(son[u]!=u)point_modi(1,1,n,pos[son[u]],-c); range_modi(1,1,n,pos[top[u]],pos[u],c); path_modi(fa[top[u]],v,c); return; } if(dep[u]>dep[v]){int t=u;u=v;v=t;} point_modi(1,1,n,pos[u],c); if(son[v])point_modi(1,1,n,pos[son[v]],-c); range_modi(1,1,n,pos[u],pos[v],c); return; } /*============================** *************主程序段************ **============================*/ int main(){ n=read(); for(int i=2;i<=n;i++){ int u=read()+1; int v=read()+1; add(u,v); add(v,u); } for(int i=1;i<=n;i++)val[i]=read(); init(); build(1,1,n); int q=read(); while(q--){ char op=0; while(op!=‘F‘&&op!=‘C‘)op=getchar(); if(op==‘C‘){ int a=read()+1; int b=read()+1; int c=read(); path_modi(a,b,c); }else{ int a=read()+1; int b=read()+1; printf("%d\n",path_query(a,b)); } } return 0; }
CC DGCD:Dynamic GCD——題解