雨天的尾巴题目解析

雨天的尾巴题解

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

心路历程:

其实考试时候还是有可能做出来的,当然关键在能否想到线段树合并。

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

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

现在看来倍增真是一点不难啊好打有好用,所以不要有为难情绪,刚就完了。(平日板子要多打记熟啊)

之所以没想到线段树合并是因为当时真的没有透彻理解,

所以新知识点还是要知道它能干什么,知道它的用处。

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

以前一个物品的题直接dfs,lca树上差分就行,现在有109个(离散后105个),空间时间不可能一个一个去维护所以 得用线段树合并。

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

每个点有很多信息所以权值线段树用来优化空间(当然也能优化时间),对每个点动态开树插入和删除(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。

优化:插入时如果lcax||lcay,那就插入了一次删了一次所以干脆不插入。。。

代码:
#include
#include
#include
#include
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[maxn50],lc[maxn50],rc[maxn50],maxx[maxn50],num[maxn50];//线段树
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(xy) 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(lr)
{
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(xkpx[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]);
}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值