您的位置:首页 > 其它

BZOJ 3631 [JLOI2014]松鼠的新家==树剖

2016-07-19 19:26 381 查看
题目传送门:23333

十分考验树剖的本事

在网上看到几个大神写树剖T掉了233333

主要是树剖,剖完后把一条路上的点不停地打永久标记,不用向下推,查询时直接把flag加起来就好了。

另外除了第一个点外其余点都要减一,中间的点进入会拿一颗糖,出时也会计算一个,所以要减去。

最后一个房间的糖题目说了不用,所以也要减。

(虽说被这个坑了好久QAQ)

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>
#define rep(j,k,l) for (int j=k;j<=l;j++)
#define N 300005

using namespace std;
struct _233{

int l,r,flag;

} tr[N*4];
int n,cnt,a
,ne[N*2],to[N*2],st
;
int as
,size
,son
,deep
,fa
,top
,dfn
,id
;

void add(int k,int l,int p){

to[p]=l;
ne[p]=st[k];
st[k]=p;

}

void dfs1(int rt,int dad){

size[rt]=1;
fa[rt]=dad;
deep[rt]=deep[dad]+1;
son[rt]=0;int _=0;
for (int i=st[rt];i!=0;i=ne[i])
if (to[i]!=dad){

dfs1(to[i],rt);
size[rt]+=size[to[i]];
if (size[to[i]]>_){

_=size[to[i]];
son[rt]=to[i];

}

}

}

void dfs2(int rt,bool qaz){

if (qaz) top[rt]=top[fa[rt]];
else top[rt]=rt;
dfn[++cnt]=rt;
id[rt]=cnt;
if (son[rt]!=0) dfs2(son[rt],1);
for (int i=st[rt];i!=0;i=ne[i])
if (to[i]!=fa[rt]&&to[i]!=son[rt])
dfs2(to[i],0);

}

void stree(int k,int l,int r){

if (l==r) return;
tr[k].l=++cnt;
tr[k].r=++cnt;
stree(tr[k].l,l,(l+r)/2);
stree(tr[k].r,(l+r)/2+1,r);

}

void change(int k,int l,int r,int o,int p){

if (o>r||p<l) return;
if (o<=l&&r<=p){

tr[k].flag+=1;
return;

}
change(tr[k].l,l,(l+r)/2,o,p);
change(tr[k].r,(l+r)/2+1,r,o,p);
return;

}

void work(int x,int y){

for (;top[x]!=top[y];x=fa[top[x]]){

if (deep[top[x]]<deep[top[y]]) swap(x,y);
change(1,1,n,id[top[x]],id[x]);
//printf("%d %d\n",top[x],x);

}
change(1,1,n,min(id[x],id[y]),max(id[x],id[y]));
//printf("%d %d\n",min(id[x],id[y]),max(id[x],id[y]));
//printf("\n");

}

void print(int k,int l,int r,int f){

if (l==r){

if (dfn[l]==a[1]) f++;
as[dfn[l]]=f+tr[k].flag;
return;

}
print(tr[k].l,l,(l+r)/2,f+tr[k].flag);
print(tr[k].r,(l+r)/2+1,r,f+tr[k].flag);

}

void tiaoshi(int k,int l,int r){

printf("%d %d %d\n",l,r,tr[k].flag);
if (l==r) return;
tiaoshi(tr[k].l,l,(l+r)/2);
tiaoshi(tr[k].r,(l+r)/2+1,r);

}

int main(){

scanf("%d",&n);
rep(i,1,n) scanf("%d",&a[i]);
rep(i,1,n-1){

int k,l;
scanf("%d%d",&k,&l);
add(k,l,2*i-1);
add(l,k,2*i);

}
dfs1(1,0);
dfs2(1,0);
cnt=1;
stree(1,1,n);
//for(int i=1;i<=5;i++) printf("%d\n",top[i]);
rep(i,2,n) work(a[i],a[i-1]);//tiaoshi(1,1,n),printf("\n");
print(1,1,n,0);
rep(i,1,n) printf("%d\n",as[i]-1);
system("pause");

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