您的位置:首页 > 理论基础 > 计算机网络

HNOI2016 Day2 T2 网络<树链剖分>

2016-05-16 21:01 567 查看

题意



分析

考虑树链剖分。

用线段树搞,线段树上每个点开一个优先队列(大根对)。

每次有新的交互(u,v),就把不在(u,v)路径上的点加入一个v值。

查询时,就查这个点的top。

因为要删除,把优先队列换种写法,一个add队列,一个del队列,具体看代码。

应该是最好理解的做法了,但并不好打。

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
using namespace std;
const int maxn=100000+10;
int n,m,q1[2*maxn],q2[2*maxn],q3[2*maxn];
//邻接表
struct Adjacency_list{
int tot=0;          //总边数(从零开始计数,使得e的反向边为e^1)
int first[maxn];    //该点连的第一条边(最晚加进来的一条边)
struct edge{
int to,next;
}e[maxn];
void init(int n){   //初始化0~n点的first
for(int i=0;i<=n;i++) first[i]=-1;
}
void addedge(int u,int v){ //在u与v之间连一条无边权的无向边(即u->v,v->u)
e[tot].to=v;
e[tot].next=first[u];
first[u]=tot++;
e[tot].to=u;
e[tot].next=first[v];
first[v]=tot++;
}
}a;
//线段树
struct Segment_tree{
priority_queue<int,vector<int>,less<int> > a[maxn*4],b[maxn*4];   //维护线段树每个点最大重要度,a维护加入,b维护删除
void Add(int u,int v) {
//fprintf(stderr,"%d add %d\n",u,v);
a[u].push(v);}
void Del(int u,int v) {
//fprintf(stderr,"%d del %d\n",u,v);
b[u].push(v);}
int Top(int u){
while(!b[u].empty()&&b[u].top()==a[u].top())
a[u].pop(),b[u].pop();
if(a[u].empty()) return -1;
else return a[u].top();
}
//把y1~y2的值加v(也可用来建树)
int y1,y2,v;
void update(int o,int l,int r){
int lc=o*2,rc=o*2+1;         //左右儿子
int mid=(l+r)>>1;
if(y1<=l&&y2>=r) Add(o,v);
else{
if(y1<=mid) update(lc,l,mid);
if(y2>mid) update(rc,mid+1,r);
}
}
//把y1~y2的值删去v
void erase(int o,int l,int r){
int lc=o*2,rc=o*2+1;         //左右儿子
int mid=(l+r)>>1;
if(y1<=l&&y2>=r) Del(o,v);
//if(y1<=l&&y2>=r&&o==1&&v==0) y1=y1;
else{
if(y1<=mid) erase(lc,l,mid);
if(y2>mid) erase(rc,mid+1,r);
}
}
//查询y1
int _max;
void query(int o,int l,int r){
if(l==r){
_max=max(Top(o),_max);
return;
}
else{
int lc=o*2,rc=o*2+1;         //左右儿子
int mid=(l+r)>>1;
_max=max(_max,Top(o));
if(y1>mid) query(rc,mid+1,r);
else query(lc,l,mid);
}
}
}l;
//树链剖分
int dep[maxn],siz[maxn],fa[maxn],son[maxn],id[maxn],val[maxn],top[maxn];  //top最近的重链父节点
int num;
void dfs1(int u,int f,int d){
dep[u]=d;
siz[u]=1;
son[u]=0;
fa[u]=f;
for(int i=a.first[u];i!=-1;i=a.e[i].next){
int v=a.e[i].to;
if(v!=f){
dfs1(v,u,d+1);
siz[u]+=siz[v];
if(siz[son[u]]<siz[v])
son[u]=v;
}
}
}
void dfs2(int u,int tp){
top[u]=tp;
id[u]=++num;
if(son[u]) dfs2(son[u],tp);
for(int i=a.first[u];i!=-1;i=a.e[i].next){
int v=a.e[i].to;
if(v!=fa[u]&&v!=son[u]){
dfs2(v,v);
}
}
}
//************************************************************************************************************
int totp;
struct line{
int l,r;
}p[25];
bool operator < (const line& l1,const line& l2){
return l1.l<l2.l||(l1.l==l2.l&&l1.r<l2.r);
}
void find(int u,int v){
if(top[u]==top[v])   //属于同一条重链
{
++totp;
p[totp].l=id[u];
p[totp].r=id[v];
if(p[totp].l>p[totp].r) swap(p[totp].l,p[totp].r);
}
else{
if(dep[top[u]]!=dep[top[v]]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
++totp;
p[totp].r=id[u];
p[totp].l=id[top[u]];
find(fa[top[u]],v);
}
else{
++totp;
p[totp].r=id[u];
p[totp].l=id[top[u]];
++totp;
p[totp].r=id[v];
p[totp].l=id[top[v]];
find(fa[top[u]],fa[top[v]]);
}
}
}
void operation1(int u,int v,int w){
totp=0;
find(u,v);
sort(p+1,p+totp+1);
p[0].r=0;p[totp+1].l=n+1;
for(int i=0;i<=totp;i++){
l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=w;
if(l.y1<=l.y2) l.update(1,1,n);
}
}
void operation2(int t){
totp=0;
find(q1[t],q2[t]);
sort(p+1,p+totp+1);
p[0].r=0;p[totp+1].l=n+1;
for(int i=0;i<=totp;i++){
l.y1=p[i].r+1;l.y2=p[i+1].l-1;l.v=q3[t];
if(l.y1<=l.y2) l.erase(1,1,n);
}
}
int operation3(int x){
l._max=-1;
l.y1=id[x];
l.query(1,1,n);
return l._max;
}
//************************************************************************************************************
int main()
{
//freopen("network.in","r",stdin);
//freopen("network.out","w",stdout);
cin>>n>>m;
a.init(n);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
a.addedge(u,v);
}
dfs1(1,0,1);
dfs2(1,1);
for(int i=1;i<=m;i++){
int start;
scanf("%d",&start);
//int xxxx=operation3(3);
//printf("(1)------》%d\n",xxxx);
if(start==0){
scanf("%d%d%d",&q1[i],&q2[i],&q3[i]);
operation1(q1[i],q2[i],q3[i]);
}
else if(start==1){
int tt;
scanf("%d",&tt);
operation2(tt);
}
else{
int xx;
scanf("%d",&xx);
printf("%d\n",operation3(xx));
}
}
return 0;
}
/*
13 23
1 2
1 3
2 4
2 5
3 6
3 7
4 8
4 9
6 10
6 11
7 12
7 13
2 1
0 8 13 3
0 9 12 5
2 9
2 8
2 2
0 10 12 1
2 2
1 3
2 7
2 1
0 9 5 6
2 4
2 5
1 7
0 9 12 4
0 10 5 7
2 1
2 4
2 12
1 2
2 5
2 3
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息