HNOI2016 网络

 身为一个强省(HN)+强校(CJ)的蒟蒻,天天gi烂。。我还能说什么呢。

于是在一堆大佬的鼓(you)励(pian)下,去做了一下HNOI2016的网络。。。

(其实是一位名叫网管的人给我们的LCA练习题(rand的))

至于正解,当年HNOI2016考场上没有人做出正解来,所以我肯定只会打暴力。

1.首先这是一堆对于链上的操作,所以我们很容易联想到树链剖分。

2.然后要求不被影响的最大值,即不经过他的最大值,这可以想到用堆来维护。

4.因为设计删除操作,我们就可以维护一个加入堆和一个删除堆,要top的时候如果两个堆的队首相同,就一直pop;

5.运用正难则反的思想,既然维护经过他的很难的话,那我们就对树链剖分后的线段树的每个节点维护不经过他的最大值;

6.那么如何维护不经过他的呢?首先在树链剖分跳LCA的时候,把跳的那些线段全部记录下来,因为跳的这些线段都是连续的,所以我们排一遍序,取这些夹在线段中间的区间进行修改即可。

7.而查询的时候就一路查下来并不断取MAX即可;

// MADE BY QT666
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<queue>
#include<set>
#include<cstdlib>
#include<cstring>
#include<string>
#include<ctime>
#define lson num<<1
#define rson num<<1|1
using namespace std;
typedef long long ll;
const int N=300050;
int gi()
{
  int x=0,flag=1;
  char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
  while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
  return x*flag;
}
int head[N],nxt[N*2],to[N*2],dfn[N],top[N],size[N],son[N],sum,dep[N],fa[N],n,m,tt;
struct ac
{
  priority_queue<int>a,d;
  void push(int x) {a.push(x);}
  void del(int x) {d.push(x);}
  int top()
  {
    while(!d.empty()&&a.top()==d.top()) a.pop(),d.pop();
	if(a.empty()) return -1;
	return a.top();
  }
}tree[N*5];
struct AC
{
  int l,r;
}Data[N];
struct Ac
{
  int x,y,z;
}q[N];
void dfs1(int x,int f)
{
  dep[x]=dep[f]+1;size[x]=1;
  for(int i=head[x];i;i=nxt[i])
    {
      int y=to[i];
      if(y!=f)
	{
	  dfs1(y,x);
	  fa[y]=x;
	  size[x]+=size[y];
	  if(size[y]>size[son[x]]) son[x]=y;
	}
    }
}
void dfs2(int x,int f)
{
  dfn[x]=++sum,top[x]=f;
  if(son[x]) dfs2(son[x],f);
  for(int i=head[x];i;i=nxt[i])
    {
      int y=to[i];
      if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
    }
}
void modify(int num,int l,int r,int L,int R,int type,int val)
{
  if(L>R) return;
  if(L<=l&&r<=R)
    {
      if(!type) tree[num].push(val);
      else tree[num].del(val);
      return;
    }
  int mid=(l+r)>>1;
  if(L<=mid) modify(lson,l,mid,L,R,type,val);
  if(R>mid) modify(rson,mid+1,r,L,R,type,val);
}
bool cmp(AC a,AC b)
{
  return a.l<b.l;
}
void update(int x,int y,int type,int val)
{
  int tot=0;
  while(top[x]!=top[y])
    {
      if(dep[top[x]]<dep[top[y]]) swap(x,y);
      Data[++tot]=(AC){dfn[top[x]],dfn[x]};x=fa[top[x]];
    }
  if(dep[x]<dep[y]) swap(x,y);
  Data[++tot]=(AC){dfn[y],dfn[x]};
  sort(Data+1,Data+1+tot,cmp);
  int last=1;
  for(int i=1;i<=tot;i++) modify(1,1,n,last,Data[i].l-1,type,val),last=Data[i].r+1;
  modify(1,1,n,last,n,type,val);
}
int query(int num,int l,int r,int x)
{
  if(l==r) return tree[num].top();
  int mid=(l+r)>>1;
  if(x<=mid) return max(tree[num].top(),query(lson,l,mid,x));
  else return max(tree[num].top(),query(rson,mid+1,r,x));
}
int main()
{
  int x,y,z,type;
  n=gi(),m=gi();
  for(int i=1;i<n;i++)
    {
      x=gi(),y=gi();
      to[++tt]=y,nxt[tt]=head[x],head[x]=tt;
      to[++tt]=x,nxt[tt]=head[y],head[y]=tt;
    }
  dfs1(1,0),dfs2(1,1);
  for(int i=1;i<=m;i++)
    {
      type=gi();
      if(type==0)
	{
	  x=gi(),y=gi(),z=gi();
	  update(x,y,0,z);
	  q[i]=(Ac){x,y,z};
	}
      if(type==1)
	{
	  x=gi();
	  update(q[x].x,q[x].y,1,q[x].z);
	}
      if(type==2)
	{
	  x=gi();
	  printf("%d\n",query(1,1,n,dfn[x]));
	}
    }
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值