雨天的尾巴(代码片段)

three-d three-d     2022-12-21     222

关键词:

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

雨天的尾巴(代码片段)

考试的时候直接扎第一题上了这到题连暴力都没打出来T_T;心路历程:当时想到了离散化(很慌没打出来。。。),树上差分,lca倍增,当时觉滴倍增很难打,一看n<100000,于是选择用向上标记法,然而少了一行代码,,,,爆... 查看详情

gdoi2014模拟雨天的尾巴(代码片段)

题目深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮食被... 查看详情

luogu4556雨天的尾巴树上差分线段树合并(代码片段)

传送门 一个套路题……树上差分+线段树合并即可注意一个细节:$pushup$的时候如果最大值为$0$一定要把最大值对应的答案也设为$0$,否则会$WA$第二个点另外如果这道题空限变小了请不要交这份代码,因为这份代码没有卡空... 查看详情

[vani有约会]雨天的尾巴(代码片段)

我之前考试是遇到过这题,但是数据范围k<=20,状压就能过。结果原题范围k<=100000……果断线段树合并。普及线段树合并:比如两个相同大小的线段树,将b树各个区间上的值合并到a树上,从树根开始合并,然后递归合并左右... 查看详情

luogu4556雨天的尾巴(线段树合并+差分)(代码片段)

题目背景深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的粮... 查看详情

bzoj3307雨天的尾巴(可持久化线段树合并)(代码片段)

题目大意:一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多。解题思路:假如说物品数量少到可以暴力添加,且树点极少,我们怎么做。首先在一个树节点上标记出哪些物品有多少,寻找道路上的节点暴力添... 查看详情

p4556[vani有约会]雨天的尾巴(线段树合并)(代码片段)

传送门一道线段树合并首先不难看出树上差分我们把每一次修改拆成四个,在(u,v)分别放上一个,在(lca)和(fa[lca])各减去一个,那么只要统计一下子树里的总数即可然而问题就在于怎么统计。直接暴力肯定是要咕咕的,那么线段... 查看详情

权值线段树-动态开点-合并(p4556[vani有约会]雨天的尾巴(代码片段)

题意:https://www.luogu.com.cn/problem/P4556树链加数,问你每个节点最多的是哪个数。思路:树链加数很容易想到差分。从下往上用权值线段树合并即可,直接用pushup把答案存在树根即可,不用每次查询最多的数1structEDGE23intto,next;4edge[N... 查看详情

p4556[vani有约会]雨天的尾巴(线段树合并+树上差分)(代码片段)

传送门题意:给一颗树,n个节点,m次操作。每次操作使u到v的路径上每个节点中颜色z的数量加1,最后询问每个节点中数量最多的颜色。思路:显然,我们得维护每个节点中颜色的最大值。那么我们给每个... 查看详情

p4556[vani有约会]雨天的尾巴(线段树合并+树上差分)(代码片段)

传送门题意:给一颗树,n个节点,m次操作。每次操作使u到v的路径上每个节点中颜色z的数量加1,最后询问每个节点中数量最多的颜色。思路:显然,我们得维护每个节点中颜色的最大值。那么我们给每个... 查看详情

[bzoj3307]雨天的尾巴(代码片段)

DescriptionN个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。Input第一行数字N,M接下来N-1行,每行两个数字a,b,表示a与b... 查看详情

bzoj3307:雨天的尾巴

3307:雨天的尾巴TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 479  Solved: 214[Submit][Status][Discuss]DescriptionN个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的 查看详情

[bzoj3307]雨天的尾巴

3307:雨天的尾巴TimeLimit: 10Sec  MemoryLimit: 128MBSubmit: 709  Solved: 296[Submit][Status][Discuss]DescriptionN个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的 查看详情

bzoj3307雨天的尾巴

3307:雨天的尾巴TimeLimit: 10Sec  MemoryLimit: 128MBDescriptionN个点,形成一个树状结构。有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成所有发放后,每个点存放最多的是哪种物品。... 查看详情

gdoi模拟雨天的尾巴树套树

雨天的尾巴深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的... 查看详情

gdoi模拟雨天的尾巴树套树

雨天的尾巴深绘里一直很讨厌雨天。灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切。虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地里的... 查看详情

bzoj-3307:雨天的尾巴

咱可以差分一下,把$u-v$这条路径上的$z$都加$1$变成$u$和$v$的$z$加$1$,$lca$和$fa_{lca}$的$z$减$1$。用线段树实现最大值的查询,最后$dfs$自底向上一路合并并查询即可。先开始线段树数组开小了,$RE$了一次。1#include<cassert>2#inclu... 查看详情

bzoj3307雨天的尾巴

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3307【题解】这什么垃圾题啊卡空间卡时间卡栈然后我会了一种新姿势:人工栈(好像也不难啊喂)我们发现对于每种物品,只需要在u这地方的权值线段树上+1,v的权值线段树上+1,LC... 查看详情