/*查找更新等操作 ?用新編號ne 變為有序的,再用線段樹?
ne[] 存的是dfs序編號 ?保證每個重鏈和子樹都是編號連續的?
有序區間才能用線段樹 。所以l,r這些都是新編號,輸入里的是舊編號*/
//找了半天讀不全的錯誤?
????????移位一定要加括號!!!!
????????i<<1|1=3
????????(i<<1)+1=3
????????i<<1+1=4 ??
? ? ? que的返回值是val 所以是ll?
//mid和m別寫混了。因為m一般定義為總量,所以以后中間都用mid!!!
//由于函數的參數比較多,調用函數的次數也比較多,所以參數的順序盡量有規律?
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e4+5;
int m,n,p,size[maxn],deep[maxn],f[maxn],son[maxn];
int cnt,head[maxn],nid[maxn],oid[maxn],ncnt,top[maxn];
ll a[maxn];
struct stree{ll value,lazy;
}t[maxn<<2];//線段樹范圍是4倍
struct ss{int to,nex;}g[maxn<<1];//g是結構體 沒法memset
void create(int u,int v){g[++cnt]={v,head[u]}; head[u]=cnt;
}
//往下走 找重鏈和重兒子son[]
void dfs1(int x,int fath){size[x]=1;deep[x]=deep[fath]+1;son[x]=0;f[x]=fath;for(int i=head[x];i;i=g[i].nex){int v=g[i].to;if(v==fath) continue;//不能往上走dfs1(v,x);size[x]+=size[v];//更新以x為根的樹的大小if(size[v]>size[son[x]]) son[x]=v;}
}
void dfs2(int x,int topx){top[x]=topx;//注意 topx不要定義成全局 遞歸調用時會亂 nid[x]=++ncnt;oid[ncnt]=x;//因為neid初始化為0,要從1開始 所以++得在前 //有重兒子的話,先遍歷重鏈,賦值nid,oidif(son[x]) dfs2(son[x],topx);//再遍歷輕鏈for(int i=head[x];i;i=g[i].nex){int v=g[i].to;if(v!=f[x]&&v!=son[x]){dfs2(v,v);}}
}void build(int l=1,int r=n,int rt=1){//建線段樹 t[rt].lazy=0;//建樹時給每個點lazy賦初值,所以lazy在外面 。若在l==r時執行 只有葉節點 if(l==r){t[rt].value=a[oid[l]];//因為a[]下標存的是舊id return;}int mid=(l+r)>>1;build(l,mid,rt<<1); build(mid+1,r,rt<<1|1);t[rt].value=t[rt<<1].value+t[rt<<1|1].value;//構造都要pushup
}
//lazy value更新都是 加上(減去)用+= 。變為 用=
void pushdown(int ln,int rn,int rt){if(t[rt].lazy){t[rt<<1].value+=t[rt].lazy*ln;t[rt<<1|1].value+=t[rt].lazy*rn;t[rt<<1].lazy+=t[rt].lazy;t[rt<<1|1].lazy+=t[rt].lazy;}t[rt].lazy=0;
}
void update(ll k,int L,int R,int l=1,int r=n,int rt=1){if(L>r||R<l) return ;if(L<=l&&r<=R){t[rt].value+=k*(r-l+1);t[rt].lazy+=k; return ;}int mid=(l+r)>>1; pushdown(mid-l+1,r-mid,rt);update(k,L,R,l,mid,rt<<1);update(k,L,R,mid+1,r,rt<<1|1);//該題是單點查詢,所以不用pushup求和
}
ll que(int k,int l=1,int r=n,int rt=1){if(k<l||k>r) return 0;//超出范圍回0,所以后面可以直接返回左右相加 if(l==r) return t[rt].value;int mid=(l+r)>>1;pushdown(mid-l+1,r-mid,rt);//有lazy所以mid后面都要pushdown 才能保證value是正確的 return que(k,l,mid,rt<<1)+que(k,mid+1,r,rt<<1|1);
}
void change(int x,int y,ll k){while(top[x]!=top[y]){ if(deep[top[x]]<deep[top[y]]) swap(x,y); update(k,nid[top[x]],nid[x]); //更新深度大的那條鏈,更新完了再向上跳 //topx和x是舊編碼,要用線段樹得用新編碼,所以得用nidx=f[top[x]];}
//前面是while所以一直跳到top相等 即xy在同一重鏈上(dfs序連續可轉為線段樹)再更新x到y區間if(deep[x]>deep[y]) swap(x,y);; update(k,nid[x],nid[y]);
}
//change:找到最近公共祖先 并分段update int main(){int x,y;ll k; while(~scanf("%d%d%d",&n,&m,&p)){ cnt=ncnt=0;for(int i=1;i<=n;i++){head[i]=0; scanf("%lld",&a[i]);}for(int i=1;i<=m;i++){scanf("%d%d",&x,&y);create(x,y);create(y,x);}dfs1(1,0);dfs2(1,1); build();for(int i=1;i<=p;i++){char ch[10];scanf("%s",ch);//%s遇空格結束 if(ch[0]=='Q') {scanf("%d",&x);printf("%lld\n",que(nid[x]));} else{scanf("%d%d%lld",&x,&y,&k);if(ch[0]=='I') change(x,y,k);else change(x,y,-k);}}}return 0;
}
總結
以上是生活随笔為你收集整理的hdu3966树链剖分 分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。