码迷,mamicode.com
首页 > 其他好文 > 详细

雨天的尾巴

时间:2019-06-20 12:26:06      阅读:88      评论:0      收藏:0      [点我收藏+]

标签:namespace   wap   memset   add   区间   bottom   ems   lse   很多   

考试的时候直接扎第一题上了这到题连暴力都没打出来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]);
   }
}

雨天的尾巴

标签:namespace   wap   memset   add   区间   bottom   ems   lse   很多   

原文地址:https://www.cnblogs.com/three-D/p/11057979.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!