雨天的尾巴

Posted three-d

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了雨天的尾巴相关的知识,希望对你有一定的参考价值。

考试的时候直接扎第一题上了这到题连暴力都没打出来T_T;

心路历程:

当时想到了离散化(很慌没打出来。。。),树上差分,lca倍增,当时觉滴倍增很难打,一看n<100000,于是选择

用向上标记法,然而少了一行代码,,,,爆零两行泪。。。

现在看来倍增真是一点不难啊好打有好用,所以不要有为难情绪,刚就完了。

之所以没想到线段树合并是因为当时真的没有透彻理解,所以总结发现新知识点还是要知道它能干什么,知道它的优点。。。

离散化用来干掉1->10^9,考试的时候真的傻认为要是有10^9种不就玩了吗,,,然后发现还有m次操作这东东,所以z离散化后len最大也就m个卡掉了很多

所以得离线来做(我承认现在才知道离线在线是嘛玩意。。丢人啊。。。)

每个点有很多信息所以权值线段树用来优化空间(当然也能优化时间),对每个点动态开树插入和删除(lca,f[lca]),最后dfs,父亲合并儿子。

所以需维护区间的maxcnt以及其id,在merge时就需要多传一下l,r(1,len),如果l==r更新maxx值和id,需要注意的是如果maxx<=0,id干成0(题目要求)。

sd错误:merge时忘了加上root[x]=merge,如果root[x]=0,就会...炸。还有空间没开够得开到maxn*50。

优化:插入时如果lca==x||lca==y,那就插入了一次删了一次所以干脆不插入。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=100050;
bool mark[maxn];
int n,m,t,ans[maxn],len;
int kpx[maxn],kpy[maxn],kpz[maxn],turn[maxn];//离线离散化
int deep[maxn],f[maxn][20];//倍增lca
int sz,root[maxn],cnt[maxn*50],lc[maxn*50],rc[maxn*50],maxx[maxn*50],num[maxn*50];//线段树
int head[maxn],cntn=1;
struct node
  int to,next;
line[maxn*2];
void add(int x,int y)

   line[cntn].to=y;
   line[cntn].next=head[x];
   head[x]=cntn++;

void dfs(int x)
 
    for(int i=head[x];i;i=line[i].next)
    
	int v=line[i].to;
        if(!mark[v])
	
	    mark[v]=1;
            deep[v]=deep[x]+1;
	    f[v][0]=x;
            for(int j=1;j<=t;j++)
            	f[v][j]=f[f[v][j-1]][j-1];
            dfs(v);
	
    


int ask(int x,int y)

    if(deep[x]>deep[y]) swap(x,y);
    for(int j=t;j>=0;j--) 
       if(deep[f[y][j]]>=deep[x])  y=f[y][j];
    if(x==y) return x;
    for(int j=t;j>=0;j--)
    
	if(f[x][j]!=f[y][j])
	
	    x=f[x][j];
	    y=f[y][j];
	
    
    return f[x][0];

void insert(int &root,int l,int r,int x)

    if(!root) root=++sz;
    cnt[root]++;
    if(l==r)
    
	maxx[root]=cnt[root];
	num[root]=maxx[root]<=0?0:l;
	return;
    
    int mid=(l+r)/2;
    if(x<=mid) insert(lc[root],l,mid,x);
    else insert(rc[root],mid+1,r,x);
    if(maxx[lc[root]]>=maxx[rc[root]])  maxx[root]=maxx[lc[root]],num[root]=num[lc[root]];
    else maxx[root]=maxx[rc[root]],num[root]=num[rc[root]];

void decrease(int &root,int l,int r,int x)

    if(!root) root=++sz;
    cnt[root]--;
    if(l==r)
    
	maxx[root]=cnt[root];
	num[root]=maxx[root]<=0?0:l;
	return;
    
    int mid=(l+r)/2;
    if(x<=mid) decrease(lc[root],l,mid,x);
    else decrease(rc[root],mid+1,r,x);
    if(maxx[lc[root]]>=maxx[rc[root]])  maxx[root]=maxx[lc[root]],num[root]=num[lc[root]];
    else maxx[root]=maxx[rc[root]],num[root]=num[rc[root]];

int merge(int x,int y,int l,int r)

    if(!x||!y)	return x+y;
    cnt[x]+=cnt[y];
    if(l==r)
    
        maxx[x]=cnt[x];
	num[x]=maxx[x]<=0?0:l;
        return x;
    
    int mid=(l+r)/2;
    lc[x]=merge(lc[x],lc[y],l,mid);
    rc[x]=merge(rc[x],rc[y],mid+1,r);
    if(maxx[lc[x]]>=maxx[rc[x]])  maxx[x]=maxx[lc[x]],num[x]=num[lc[x]];
    else maxx[x]=maxx[rc[x]],num[x]=num[rc[x]];
    return x;

void dfst(int x)

    for(int i=head[x];i;i=line[i].next)
    
	int v=line[i].to;
	if(!mark[v])
	
	    mark[v]=1;
	    dfst(v);
	    root[x]=merge(root[x],root[v],1,len);
	
    
    ans[x]=turn[num[root[x]]];

int main()
   int x,y;
   scanf("%d%d",&n,&m);
   while( (1<<(t+1)) <=n) t++;
   for(int i=1;i<n;i++)
   
	scanf("%d%d",&x,&y);
 	add(x,y);
	add(y,x);
   
   deep[1]=1;
   mark[1]=1;
   dfs(1);
   for(int i=1;i<=m;i++)
   
      scanf("%d%d%d",&kpx[i],&kpy[i],&kpz[i]);
      turn[i]=kpz[i];
   
   sort(turn+1,turn+1+m);
   len=unique(turn+1,turn+1+m)-(turn+1);
   for(int i=1;i<=m;i++)
   
      kpz[i]=lower_bound(turn+1,turn+1+len,kpz[i])-turn;
   
   for(int i=1;i<=m;i++)
   
	x=ask(kpx[i],kpy[i]);
        if(x==kpx[i])
        
	    insert(root[ kpy[i] ],1,len,kpz[i]);
            decrease(root[ f[x][0] ],1,len,kpz[i]);
            continue;
        
        if(x==kpy[i])
        
            insert(root[ kpx[i] ],1,len,kpz[i]);
            decrease(root[ f[x][0] ],1,len,kpz[i]);
            continue;
        
	insert(root[ kpx[i] ],1,len,kpz[i]);
        insert(root[ kpy[i] ],1,len,kpz[i]);
        decrease(root[x],1,len,kpz[i]);
        decrease(root[ f[x][0] ],1,len,kpz[i]);
   
   memset(mark,0,sizeof(mark));
   mark[1]=1;
   dfst(1);
   for(int i=1;i<=n;i++)
   
	printf("%d\n",ans[i]);
   

以上是关于雨天的尾巴的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ 3307]雨天的尾巴

Bzoj 3307 雨天的尾巴

GDOI模拟雨天的尾巴树套树

GDOI模拟雨天的尾巴树套树

[bzoj3307]雨天的尾巴_线段树合并

bzoj3307:雨天的尾巴