标签:
sth神犇的模板:
//bzoj1036 题目:一个n个点的树每个点有一个权值,支持修改单点权值,求某两点路径上的点权和或最大点权。 #include <cstdio> using namespace std; int pos[30001],f[30001],up[30001],son[30001],size[30001],a[80001],next[80001],last[30001],sum[100001],max[100001];//pos是指某点在线段树中的位置;f是父节点;up是所在链的最上端;son是众儿子中在同一链中的那一个;size是子树的点数;sum是线段树区间和;max是线段树区间最大值 int n,mm,tot,deep[30001],w[30001],q,que,ll,rr,mmax,ssum,which[30001]; char c;//w是单点权值;which是线段树某位置对应的是哪个点,可看做与pos双向映射。 void build(int x,int y) { a[++mm]=y; next[mm]=last[x]; last[x]=mm; a[++mm]=x; next[mm]=last[y]; last[y]=mm; } void dfs1(int x) { int j,mmax=0,num=0; size[x]=1; for (j=last[x];j;j=next[j]) if (a[j]!=f[x]) { f[a[j]]=x; deep[a[j]]=deep[x]+1; dfs1(a[j]); size[x]+=size[a[j]]; if (size[a[j]]>mmax) {mmax=size[a[j]]; num=a[j];} } son[x]=num; } void dfs2(int x) { pos[x]=++tot; which[tot]=x; if (!son[x]) return; up[son[x]]=up[x]; dfs2(son[x]); int j; for (j=last[x];j;j=next[j]) if (a[j]!=f[x]&&a[j]!=son[x]) { up[a[j]]=a[j]; dfs2(a[j]); } } void buildtree(int now,int l,int r) { if (l==r) { sum[now]=max[now]=w[which[l]]; return; } int x=now<<1; buildtree(x,l,(l+r)>>1); buildtree(x+1,((l+r)>>1)+1,r); if (max[x]>max[x+1]) max[now]=max[x]; else max[now]=max[x+1]; sum[now]=sum[x]+sum[x+1]; } void change(int now,int l,int r) { if (l==r) { max[now]=sum[now]=rr; return; } int mid=(l+r)>>1,x=now<<1; if (ll<=mid) change(x,l,mid); else change(x+1,mid+1,r); if (max[x]>max[x+1]) max[now]=max[x]; else max[now]=max[x+1]; sum[now]=sum[x]+sum[x+1]; } void getans(int now,int l,int r) { if (l>=ll&&r<=rr) { if (max[now]>mmax) mmax=max[now]; ssum+=sum[now]; return; } int mid=(l+r)>>1; if (ll<=mid) getans(now<<1,l,mid); if (rr>mid) getans((now<<1)+1,mid+1,r); } int main() { freopen("lx.in","r",stdin); freopen("lx.out","w",stdout); scanf("%d",&n); int i,x,y,tmp; for (i=1;i<n;i++) { scanf("%d%d",&x,&y); build(x,y); } deep[1]=1; dfs1(1); up[1]=1; dfs2(1); for (i=1;i<=n;i++) scanf("%d",&w[i]); buildtree(1,1,n); scanf("%d\n",&que); for (q=1;q<=que;q++) { c=getchar(); if (c==‘C‘) { for (i=1;i<=5;i++) c=getchar(); scanf("%d%d\n",&x,&y);//将点x的权值改为r ll=pos[x]; rr=y; change(1,1,n); } else { for (i=1;i<=3;i++) c=getchar(); scanf("%d%d\n",&x,&y); mmax=-99999999; ssum=0; while (up[x]!=up[y]) { if (deep[up[x]]<deep[up[y]]) {tmp=x; x=y; y=tmp;} ll=pos[up[x]]; rr=pos[x]; getans(1,1,n); x=f[up[x]]; } if (deep[x]>deep[y]) {tmp=x; x=y; y=tmp;} ll=pos[x]; rr=pos[y]; getans(1,1,n); if (c==‘X‘) printf("%d\n",mmax);else printf("%d\n",ssum); } } return 0; }
链剖,xyx说是链抛。给xyx神犇跪了O)Z
不说了,(;′⌒`)这是我的链剖模板。为何在codevs上总是RE?我对codevs逐渐产生了隔膜。
#include<cmath> #include<cctype> #include<cstdio> #include<cstring> #include<algorithm> #define for1(i,a,n) for(int i=(a);i<=(n);++i) #define for2(i,a,n) for(int i=(a);i<(n);++i) #define for3(i,a,n) for(int i=(a);i>=(n);++i) #define for4(i,a,n) for(int i=(a);i>(n);++i) #define CC(i,a) memset(i,a,sizeof(i)) using namespace std; inline const int max(const int &a,const int &b){return a>b?a:b;} inline const int min(const int &a,const int &b){return a<b?a:b;} inline void swapp(int &a,int &b){int c=a;a=b;b=c;} struct node{int nxt,to;}E[80003]; int N,point[30003],sum[100003],ma[100003],cnt=1,son[30003],up[30003],size[30003],deep[30003]; int pos[30003],which[30003],tot=0,a[30003],fa[30003]; inline void insect(int x,int y){E[cnt].nxt=point[x];E[cnt].to=y;point[x]=cnt++;} inline void dfs1(int x){ int nmax=0,num=0; size[x]=1; for(int tmp=point[x];tmp;tmp=E[tmp].nxt)if (E[tmp].to!=fa[x]){ fa[E[tmp].to]=x; deep[E[tmp].to]=deep[x]+1; dfs1(E[tmp].to); size[x]+=size[E[tmp].to]; if (size[E[tmp].to]>nmax){nmax=size[E[tmp].to];num=E[tmp].to;} }son[x]=num; } inline void dfs2(int x){ pos[x]=++tot;which[tot]=x; if (!son[x]) return; up[son[x]]=up[x]; dfs2(son[x]); for(int tmp=point[x];tmp;tmp=E[tmp].nxt)if ((E[tmp].to!=fa[x])&&(E[tmp].to!=son[x])){ up[E[tmp].to]=E[tmp].to; dfs2(E[tmp].to); } } inline void buildtree(int l,int r,int rt){ if (l==r){sum[rt]=ma[rt]=a[which[l]];return;} int mid=(l+r)>>1; buildtree(l,mid,rt<<1); buildtree(mid+1,r,rt<<1|1); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; ma[rt]=max(ma[rt<<1],ma[rt<<1|1]); } inline void change(int ll,int rr,int l,int r,int rt){ if (l==r){sum[rt]=ma[rt]=rr;return;} int mid=(l+r)>>1; if (ll<=mid) change(ll,rr,l,mid,rt<<1); else change(ll,rr,mid+1,r,rt<<1|1); sum[rt]=sum[rt<<1]+sum[rt<<1|1]; ma[rt]=max(ma[rt<<1],ma[rt<<1|1]); } inline int getmax(int L,int R,int l,int r,int rt){ if ((L<=l)&&(r<=R)){return ma[rt];} int mid=(l+r)>>1,s=-1E9; if (L<=mid) s=getmax(L,R,l,mid,rt<<1); if (R>mid) s=max(s,getmax(L,R,mid+1,r,rt<<1|1)); return s; } inline void query1(int x,int y){ int mmax=-1E9; while (up[x]!=up[y]){ if (deep[up[x]]<deep[up[y]])swapp(x,y); mmax=max(mmax,getmax(pos[up[x]],pos[x],1,N,1)); x=fa[up[x]]; } if (deep[x]>deep[y])swapp(x,y); mmax=max(mmax,getmax(pos[x],pos[y],1,N,1)); printf("%d\n",mmax); } inline int getsum(int L,int R,int l,int r,int rt){ if ((L<=l)&&(r<=R)){return sum[rt];} int mid=(l+r)>>1,s=0; if (L<=mid)s+=getsum(L,R,l,mid,rt<<1); if (R>mid)s+=getsum(L,R,mid+1,r,rt<<1|1); return s; } inline void query2(int x,int y){ int ssum=0; while (up[x]!=up[y]){ if (deep[up[x]]<deep[up[y]])swapp(x,y); ssum+=getsum(pos[up[x]],pos[x],1,N,1); x=fa[up[x]]; } if (deep[x]>deep[y])swapp(x,y); ssum+=getsum(pos[x],pos[y],1,N,1); printf("%d\n",ssum); } int main(){ scanf("%d\n",&N); CC(point,0);CC(deep,0);CC(size,0);CC(sum,0);CC(ma,0);CC(up,0);CC(son,0);CC(fa,0); for2(i,1,N){ int x,y;scanf("%d%d\n",&x,&y); insect(x,y);insect(y,x); }deep[1]=1; dfs1(1); up[1]=1; dfs2(1); for1(i,1,N) scanf("%d",&a[i]); buildtree(1,N,1); int que;scanf("%d\n",&que); while (que--){ char c=getchar(); if (c==‘C‘){ for1(i,1,5)c=getchar(); int ll,rr;scanf("%d%d\n",&ll,&rr); change(pos[ll],rr,1,N,1); }else{ for1(i,1,3)c=getchar(); int x,y;scanf("%d%d\n",&x,&y); if (c==‘X‘) query1(x,y); else query2(x,y); } }return 0; }
这样就可以了呢,第一次用CA爷的电脑,键盘真好使。
【BZOJ 1036】【ZJOI 2008】树的统计 树链剖分模板题
标签:
原文地址:http://www.cnblogs.com/abclzr/p/5204852.html