1. 程式人生 > >BZOJ3307: 雨天的尾巴

BZOJ3307: 雨天的尾巴

都是 UC IT != log struct || turn git

中文題意簡單易懂 不再敘述

題解: 很明顯我們考慮到運用樹上差分的思想 加入這個元素等於在u,v位置加入 刪除等於在lca(u,v)和fa[lca(u,v)]的地方-1 這樣問題就轉化成 從葉子節點dfs將這些點操作 並查詢區間num最大且vul最小的值即可 這樣我們可以通過線段樹維護 然後本題的一個難點就是線段樹合並了吧 講道理 以前的合並的題都是啟發式合並 但是這個題有個性質就是你用線段樹維護 那麽你就只需要將都有的節點從小到上更新 沒有的之間連上去即可 然後就做完了 復雜度均攤下來應該是nlogn 空間復雜度同理也是nlogn

#include <bits/stdc++.h>
#define pii pair<int,int>
const int MAXN=1e5+10;
#define ll long long
using namespace std;
int n,m;
vector<int>vec[MAXN];
ll read(){
    ll x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();}
    while(isdigit(ch))x=x*10+ch-‘0‘,ch=getchar();
    return x*f;
}
int fa[MAXN],num[MAXN],dep[MAXN],son[MAXN];
void dfs1(int v,int pre,int deep){
    num[v]=1;fa[v]=pre;dep[v]=deep+1;
    for(int i=0;i<vec[v].size();i++){
	if(vec[v][i]!=pre){
	    dfs1(vec[v][i],v,deep+1);
	    num[v]+=num[vec[v][i]];
	    if(son[v]==-1||num[son[v]]<num[vec[v][i]])son[v]=vec[v][i];
	}
    }
}
int p[MAXN],fp[MAXN],cnt,tp[MAXN],sz;
void dfs2(int v,int td){
    p[v]=++cnt;fp[p[v]]=v;tp[v]=td;
    if(son[v]!=-1)dfs2(son[v],td);
    for(int i=0;i<vec[v].size();i++){
	if(vec[v][i]!=son[v]&&vec[v][i]!=fa[v])dfs2(vec[v][i],vec[v][i]);
    }
}
int Lca(int u,int v){
    int uu=tp[u];int vv=tp[v];
    while(uu!=vv){
	if(dep[uu]<dep[vv])swap(uu,vv),swap(u,v);
	u=fa[uu];uu=tp[u];
    }
    if(dep[u]>dep[v])swap(u,v);
    return u;
}
typedef struct que{
    int u,v,c,lca;
}que;
que q[MAXN];
vector<int>v1;
vector<pii>v2[MAXN];
typedef struct node{
    int num,maxx,l,r;
}node;
node d[MAXN*16*4];int ans[MAXN],rt[MAXN];
void up(int x){
    if(!d[x].l&&!d[x].r)return ;
    d[x].num=0;
    if(d[x].l){d[x].num=d[d[x].l].num;d[x].maxx=d[d[x].l].maxx;}
    if(d[x].r){
	if(!d[x].num)d[x].num=d[d[x].r].num,d[x].maxx=d[d[x].r].maxx;
	else {
	    if(d[x].num<d[d[x].r].num)d[x].num=d[d[x].r].num,d[x].maxx=d[d[x].r].maxx;
	    else if(d[x].num==d[d[x].r].num)d[x].maxx=min(d[x].maxx,d[d[x].r].maxx);
	}
    }
}
int cnt1;
void update(int &rt,int l,int r,int t,int vul){
    if(!rt)rt=++cnt1;   
    if(l==r){d[rt].num+=vul;d[rt].maxx=l;return ;}
    int mid=(l+r)>>1;
    if(t<=mid)update(d[rt].l,l,mid,t,vul);
    else update(d[rt].r,mid+1,r,t,vul);
    up(rt);
}
void merge(int &x,int y,int l,int r){
    if(!x&&!y)return ;
    if(x&&y){
	if(l==r){
	    d[x].num+=d[y].num;return ;
	}
	int mid=(l+r)>>1;
	merge(d[x].l,d[y].l,l,mid);
	merge(d[x].r,d[y].r,mid+1,r);
    }
    else{
	if(y)x=y;
	return ;
    }
    up(x);
}
void dfs(int v){
    for(int i=0;i<vec[v].size();i++){
	if(vec[v][i]!=fa[v]){
	    dfs(vec[v][i]);
	    merge(rt[v],rt[vec[v][i]],1,sz);
	}
    }
    for(int i=0;i<v2[v].size();i++){
	update(rt[v],1,sz,v2[v][i].first,v2[v][i].second);}
   // cout<<d[rt[v]].num<<"====:::"<<" "<<v<<endl;
   // for(int i=0;i<v2[v].size();i++)cout<<v2[v][i].first<<" "<<v2[v][i].second<<endl;
    if(!d[rt[v]].num)ans[v]=0;
    else ans[v]=d[rt[v]].maxx;
}
int main(){
    n=read();m=read();
    for(int i=1;i<=n;i++)son[i]=-1;
    int u,v;
    for(int i=1;i<n;i++)u=read(),v=read(),vec[u].push_back(v),vec[v].push_back(u);
    dfs1(1,0,0);dfs2(1,1);
    for(int i=1;i<=m;i++)q[i].u=read(),q[i].v=read(),q[i].c=read(),v1.push_back(q[i].c),q[i].lca=Lca(q[i].u,q[i].v);
    //for(int i=1;i<=m;i++)cout<<q[i].lca<<" ";
    //cout<<endl;
    sort(v1.begin(),v1.end());
    sz=unique(v1.begin(),v1.end())-v1.begin();
 //   built(1,1,sz);
    for(int i=1;i<=m;i++){
	q[i].c=lower_bound(v1.begin(),v1.begin()+sz,q[i].c)-v1.begin()+1,v2[q[i].u].push_back(make_pair(q[i].c,1));
	v2[q[i].v].push_back(make_pair(q[i].c,1));v2[q[i].lca].push_back(make_pair(q[i].c,-1));
	v2[fa[q[i].lca]].push_back(make_pair(q[i].c,-1));
    }
    dfs(1);
    for(int i=1;i<=n;i++){
	if(!ans[i])puts("0");
	else printf("%d\n",v1[ans[i]-1]);
    }
    return 0;
}

3307: 雨天的尾巴

Time Limit: 10 Sec Memory Limit: 128 MB
Submit: 1004 Solved: 400
[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

BZOJ3307: 雨天的尾巴