[HDU4918]点分治+树状数组
2019-03-04 22:43
155 查看
Query on the subtree
叉姐的题 看了看聊天记录发现自己光调就是至少两个多小时...不过慢慢来吧 严格意义上讲是自从上学期final week以来复健的第一道大数据结构题...其实寒假因为突击驾照的缘故也荒废掉很多时间...
题意其实很简明扼要: 两种操作 改变树上某个点的权值 或者 询问在某个点d距离范围内的所有权值和
其实不论考不考虑权值 这道题对我来说都是不好写的 毕竟权值在这里就是要求一个树状数组而已
最大的困难还是来自于 要层层统计root贡献的时候 去重以及正确记录当前点与rt的距离!
MARK几个我wa的地方(在拍std的情况下改的还算顺利):
add&sum头一昏双双写错
内存超限/不够 据说subrt是要开nlogn的 不过100w将将也能过吧
建立一套新边表的时候时刻注意变量名...
是divide(root)而不是divide(v)
给vector init深度的时候保险起见还是要resize sum...毕竟重心只由个数决定...与深度没有绝对关系...
[code]#include<cstdio> #include<algorithm> #include<cstring> #include<vector> #define mo 1000000007 #define N 202020 #define M 4004040 #define ll long long using namespace std; int edgenum,head ,jie ,maxx[M],vet ,size ; int edgenew,headnew ,jienew[M],vetnew[M],pri[M],id[M],maxd ,disrt ; int n,Q,nowd,sum,root,f ,flag ,a ,nows; struct Tree{ int n; vector<int>t; void init(int size){ t.clear(); n=size; for(int i=0;i<=n;i++)t.push_back(0); } void add(int k,int x){ for(int i=k;i<=n;i+=i&(-i))t[i]+=x; } int sum(int k){ int ans=0; if(k<=0)return 0; for(int i=k;i>0;i-=i&(-i))ans+=t[i]; //printf("%d %d\n",k,ans); return ans; } }; Tree t ;Tree subt[1001010]; void getroot(int u,int ff,int dep){ int e=head[u];size[u]=1;f[u]=0; nowd=max(nowd,dep); while(e>0){ int v=vet[e]; if(v!=ff && flag[v]==0) {getroot(v,u,dep+1);size[u]+=size[v];f[u]=max(f[u],size[v]);} e=jie[e]; } f[u]=max(f[u],sum-size[u]); if(f[u]<f[root])root=u; } void add(int u,int v){edgenum++;vet[edgenum]=v;jie[edgenum]=head[u];head[u]=edgenum;} void addnew(int u,int anc,int subanc,int w,int ww){ //printf("=======%d %d %d %d\n",anc,subanc,u,ww); edgenew++;vetnew[edgenew]=anc;pri[edgenew]=ww; jienew[edgenew]=headnew[u]; headnew[u]=edgenew; id[edgenew]=w; } void ins(int anc,int u,int ff,int dep){ int e=head[u];disrt[u]=dep; t[anc].add(dep,a[u]); //printf("`````````````%d %d %d\n",anc,u,dep); while(e>0){ int v=vet[e]; if(v!=ff && flag[v]==0){ ins(anc,v,u,dep+1); } e=jie[e]; } } void insnew(int anc,int u,int subroot,int id,int ff,int dep){ int e=head[u]; subt[id].add(dep,a[u]); addnew(u,anc,subroot,id,disrt[u]); //printf("aaaaaaaaa====%d %d %d %d \n",anc,u,id,dep); while(e>0){ int v=vet[e]; if(v!=ff && flag[v]==0){ insnew(anc,v,subroot,id,u,dep+1); } e=jie[e]; } } void divide(int u){ int e=head[u];flag[u]=1; t[u].init(sum+1); maxd[u]=sum; while(e>0){ int v=vet[e]; if(flag[v]==0){ ins(u,v,0,1); } e=jie[e]; } e=head[u]; while(e>0){ int v=vet[e]; if(flag[v]==0){ sum=size[v]; f[root]=n+1;getroot(v,0,0); //printf("..........%d %d %d\n",u,root,nowd); nows++; maxx[nows]=sum; subt[nows].init(sum+1); //addnew(root,u,nows,disrt[root]); insnew(u,v,root,nows,0,1); divide(root); } e=jie[e]; } return; } int main(){ while(scanf("%d%d",&n,&Q)!=EOF){ for(int i=1;i<=n;i++)scanf("%d",&a[i]); edgenum=0;edgenew=0;nows=0; memset(flag,0,sizeof(flag)); memset(head,0,sizeof(head)); memset(headnew,0,sizeof(headnew)); memset(maxd,0,sizeof(maxd)); memset(maxx,0,sizeof(maxx)); for(int i=1;i<n;i++){ int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } root=0;f[root]=n+1;sum=n; nowd=0; getroot(1,0,0);int alr=root; divide(root); while(Q--){ char str[10];int u,d; scanf("%s%d%d",str,&u,&d); if(str[0]=='!'){ int e=headnew[u],dis1=0; while(e>0){ int v=vetnew[e],ii=id[e];dis1=pri[e]; t[v].add(dis1,d-a[u]); subt[ii].add(dis1,d-a[u]); e=jienew[e]; } a[u]=d; }else{ int e=headnew[u],ee=e,dis1=0,ans=a[u]+t[u].sum(min(d,maxd[u])); //printf("%d %d ???????%d\n",u,maxd[u],t[3].sum(1)); //printf("??????/%d\n",ans); while(e>0){ int v=vetnew[e],ii=id[e];dis1=pri[e]; if(d>dis1)ans+=t[v].sum(min(maxd[v],d-dis1)); if(d>=dis1)ans+=a[v]; if(d>dis1)ans-=subt[ii].sum(min(maxx[ii],d-dis1)); //printf("====%d %d %d\n",v,maxx[ii],dis1); e=jienew[e]; } printf("%d\n",ans); } } } return 0; }
过段时间要去找claris的题刷 明天先把dp题补完然后把Legilimens去年的模拟题更掉
相关文章推荐
- 洛谷P3374 【模板】树状数组 1(CDQ分治)
- UOJ276 [清华集训2016] 汽水 【二分答案】【点分治】【树状数组】
- UvaLive 6667 Longest Chain (分治求三元组LIS&树状数组)
- hdoj 1394 Minimum Inversion Number 线段树||树状数组||分治
- 【BZOJ2683】简单题 [分治][树状数组]
- BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】
- BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]
- bzoj 3262 陌上花开 - CDQ分治 - 树状数组
- BZOJ 1176 [Balkan2007]Mokia [CDQ分治+树状数组]
- 【bzoj3648】【寝室管理】【环套树+点分治+树状数组】
- BZOJ 2738 子矩阵第k大 | 二维树状数组 整体二分 分治
- BZOJ_2225_[Spoj 2371]Another Longest Increasing_CDQ 分治+树状数组
- 【BZOJ4430】[Nwerc2015]Guessing Camels赌骆驼【树状数组】【或CDQ分治】
- [HDOJ 4918] Query on the subtree [树的分治+树状数组]
- 树状数组与分治法求逆序数
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
- BZOJ 3648|寝室管理|点分治|树状数组|平衡树
- TOJ 3896 Above the Median -- 分治 树状数组
- HDU 5618 Jam's problem again(三维偏序,CDQ分治,树状数组,线段树)
- BZOJ1176【CDQ分治】【树状数组】