真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[BZOJ 3307]雨天的尾巴

3307: 雨天的尾巴

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 709  Solved: 296
[Submit][Status][Discuss]

Description

N个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。

Input

第一行数字N,M
接下来N-1行,每行两个数字a,b,表示a与b间有一条边
再接下来M行,每行三个数字x,y,z.如题

Output

输出有N行
每i行的数字表示第i个点存放最多的物品是哪一种,如果有
多种物品的数量一样,输出编号最小的。如果某个点没有物品
则输出0

Sample Input

20 50
8 6
10 6
18 6
20 10
7 20
2 18
19 8
1 6
14 20
16 10
13 19
3 14
17 18
11 19
4 11
15 14
5 18
9 10
12 15
11 14 87
12 1 87
14 3 84
17 2 36
6 5 93
17 6 87
10 14 93
5 16 78
6 15 93
15 5 16
11 8 50
17 19 50
5 4 87
15 20 78
1 17 50
20 13 87
7 15 22
16 11 94
19 8 87
18 3 93
13 13 87
2 1 87
2 6 22
5 20 84
10 12 93
18 12 87
16 10 93
8 17 93
14 7 36
7 4 22
5 9 87
13 10 16
20 11 50
9 16 84
10 17 16
19 6 87
12 2 36
20 9 94
9 2 84
14 1 94
5 5 94
8 17 16
12 8 36
20 17 78
12 18 50
16 8 94
2 19 36
10 18 36
14 19 50
4 12 50

Sample Output

87
36
84
22
87
87
22
50
84
87
50
36
87
93
36
94
16
87
50
50
1<=N,M<=100000
1<=a,b,x,y<=N
1<=z<=10^9

解题报告

线段树启发式暴力合并

首先我们肯定会想到简单的树剖套线段树套权值线段树的做法,但显然,假如数据卡你的话,是可以随便卡掉的,$MLE$+$RE$

所以我们不能在大范围的区间进行权值线段树的开点与修改,于是我们考虑差分

我们在树上的每一个节点开一棵权值线段树,动态开点保证空间,然后在树上差分,路径两端点对应加1,$LCA$与$LCA$父节点对应减1,就可以达到差分的效果了,最后$dfs$合并线段树统计答案即可

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 inline int read(){
 6     int sum(0);char ch(getchar());
 7     for(;ch<'0'||ch>'9';ch=getchar());
 8     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
 9     return sum;
10 }
11 const int mxv(1e9);
12 struct edge{int e;edge *n;}*pre[100005];
13 inline void insert(int s,int e){edge *tmp(new edge);tmp->e=e;tmp->n=pre[s];pre[s]=tmp;}
14 int n,m,fa[100005][20],dep[100005];
15 inline void dfs(int u){
16     for(int i=1;(1<<i)<=dep[u];++i)fa[u][i]=fa[fa[u][i-1]][i-1];
17     for(edge *i=pre[u];i;i=i->n){
18         int e(i->e);if(e==fa[u][0])continue;
19         fa[e][0]=u;dep[e]=dep[u]+1;dfs(e);
20     }
21 }
22 inline int lca(int x,int y){
23     if(dep[x]<dep[y])swap(x,y);
24     int delta(dep[x]-dep[y]);
25     for(int i=0;delta;++i)if(delta&(1<<i))delta^=1<<i,x=fa[x][i];
26     if(x==y)return x;
27     for(int i=19;i>=0;--i)if(fa[x][i]^fa[y][i])x=fa[x][i],y=fa[y][i];return fa[x][0];
28 }
29 #define get_mx(x) (x?x->mx:0)
30 #define get_pos(x) (x?x->pos:0)
31 struct node{
32     node *lch,*rch;
33     int mx;
34     node():lch(NULL),rch(NULL),mx(0){}
35     inline void pushup(){this->mx=max(get_mx(this->lch),get_mx(this->rch));}
36 }*root[100005];
37 inline void update(node *&x,int pos,int w,int l,int r){
38     if(!x){x=new node();}
39     if(l==r){x->mx+=w;/*cout<<' '<<l<<' '<<r<<endl;*/return;}
40     int mid((l+r)>>1);
41     if(pos<=mid)update(x->lch,pos,w,l,mid);
42     else update(x->rch,pos,w,mid+1,r);x->pushup();
43 }
44 int ans[100005];
45 inline void merge(node *&x,node *&y,int l,int r){
46     if(!y)return;if(!x){x=y;return;}
47     if(l==r){x->mx+=y->mx;return;}
48     int mid((l+r)>>1);
49     merge(x->lch,y->lch,l,mid);merge(x->rch,y->rch,mid+1,r);
50     x->pushup();
51 }
52 inline int query(node *x,int ll,int rr,int l,int r){
53     if(!x)return 0;if(ll<=l&&r<=rr)return x->mx;int mid((l+r)>>1),ret(0);
54     if(ll<=mid)ret=query(x->lch,ll,rr,l,mid);if(mid<rr)ret=max(ret,query(x->rch,ll,rr,mid+1,r));return ret;
55 }
56 inline int query_pos(node *x,int l,int r,int mx){
57     if(!x)return 0;if(l==r)return l;int mid((l+r)>>1);//cout<<l<<' '<<r<<' '<<mx<<' '<<get_mx(x->lch)<<endl;
58     if(get_mx(x->lch)==mx)return query_pos(x->lch,l,mid,mx);
59     return query_pos(x->rch,mid+1,r,mx);
60 }
61 /*inline void print(node *x){
62     if(!x)return;
63     printf("%d %d %d %d\n",x->l,x->r,x->mx,x->pos);
64     print(x->lch);print(x->rch);
65 }*/
66 inline void cal(int u){
67     for(edge *i=pre[u];i;i=i->n){
68         int e(i->e);if(e==fa[u][0])continue;
69         cal(e);merge(root[u],root[e],1,mxv);//cout<<"print "<<u<<endl;print(root[u]);
70     }
71     ans[u]=query(root[u],1,mxv,1,mxv);/*cout<<ans[u]<<' ';*/ans[u]=query_pos(root[u],1,mxv,ans[u]);//cout<<ans[u]<<endl;
72 }
73 int main(){
74     n=read(),m=read();for(int i=1;i<n;++i){int x(read()),y(read());insert(x,y);insert(y,x);}dfs(1);
75     while(m--){
76         int x(read()),y(read()),z(read()),tp(lca(x,y));
77         update(root[x],z,1,1,mxv);update(root[y],z,1,1,mxv);update(root[tp],z,-1,1,mxv);update(root[fa[tp][0]],z,-1,1,mxv);
78     }
79     cal(1);for(int i=1;i<=n;++i)printf("%d\n",ans[i]);
80 }
81 
View Code

 

posted @ 2017-10-30 09:13  Hzoi_Mafia  阅读(801)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神