您的位置:首页 > 其它

[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去年的模拟题更掉

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: