【BZOJ 4538】【HNOI 2016】网络

又是一道树剖题。。。
对每个点建一个优先队列。
对1号操作取反,比如a到b之间加入重要度为v的话,就往不是a到b路径的节点加入v;2号操作是1号操作的逆运算,对某个时间打上标记即可;对于3号操作询问,只要找一下当前节点对应的优先队列中权值最大且对应的时间没有被打上标记的就是答案。

#include<cmath>
#include<cstdio>
#include<vector>
#include <queue>
#include<cstring>
#include<iomanip>
#include<stdlib.h>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1000000000
#define mod 1000000007
#define N 100005
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct qry{int x,y;} a[105];
bool operator <(qry u,qry v) {return u.x < v.x;}
priority_queue<qry> q[300005];
int tar[N<<1],nxt[N<<1],head[N],size[N],fa[N],dep[N],son[N],top[N],id[N],hack[N<<1];
int tot,num,cnt,t,res,n,m,i,x,y,opt,aa,bb,rk;
void add_edge(int x,int y)
{tar[++tot] = y; nxt[tot] = head[x]; head[x] = tot;}
void dfs1(int nw)
{
    size[nw] = 1; int p;
    for (p = head[nw];p; p = nxt[p])
        {
            int nt = tar[p]; if (nt == fa[nw]) continue;
            fa[nt] = nw; dep[nt] = dep[nw] + 1;
            dfs1(nt); size[nw] += size[nt];
            if (size[nt] >= size[son[nw]]) son[nw] = nt;
        }
}
void dfs2(int nw,int tp)
{
    int p;
    top[nw] = tp; id[nw] = ++num; if (son[nw]) dfs2(son[nw],tp);
    for (p = head[nw];p; p = nxt[p])
        {
            int nt = tar[p];
            if (nt != fa[nw] && nt != son[nw]) dfs2(nt,nt);
        }
}
void link(int u,int v)
{
    cnt = 0;
    while (top[u] != top[v])
        {
            if (dep[top[u]] < dep[top[v]]) swap(u,v);
            a[++cnt].x = id[top[u]]; a[cnt].y = id[u];
            u = fa[top[u]];
        }
    if (dep[u] > dep[v]) swap(u,v);
    a[++cnt].x = id[u]; a[cnt].y = id[v];
}
void update(int rt,int l,int r,int L,int R)
{
    if (L <= l && r <= R) {q[rt].push((qry){rk,t}); return;}
    int mid = (l + r) >> 1;
    if (L <= mid) update(rt<<1,l,mid,L,R);
    if (mid < R) update(rt<<1|1,mid+1,r,L,R);   
}
void query(int rt,int l,int r,int target)
{
    while (!q[rt].empty() && hack[q[rt].top().y]) q[rt].pop(); //弹出栈顶已被结束的请求
    if (!q[rt].empty()) res = max(res,q[rt].top().x);
    if (l == r) return;
    int mid = (l + r) >> 1;
    if (target <= mid)  query(rt<<1,l,mid,target);
                else    query(rt<<1|1,mid+1,r,target);
}
int main()
{
    scanf("%d%d",&n,&m);
    fo(i,1,n-1) {scanf("%d%d",&x,&y); add_edge(x,y); add_edge(y,x);}
    dfs1(1); dfs2(1,1);

    fo(t,1,m)
        {
            scanf("%d",&opt);
            if (opt == 0)
                {
                    scanf("%d%d%d",&aa,&bb,&rk);
                    link(aa,bb);
                    sort(a+1,a+cnt+1);
                    fo(i,1,cnt) if (a[i-1].y+1 <= a[i].x-1) update(1,1,n,a[i-1].y+1,a[i].x-1);
                    if (a[cnt].y+1 <= n) update(1,1,n,a[cnt].y+1,n);
                    //对操作区间取反 
                }
            if (opt == 1) {scanf("%d",&aa); hack[aa] = 1;}  //结束某个请求 
            if (opt == 2)
                {
                    scanf("%d",&aa); res = -1;
                    query(1,1,n,id[aa]); printf("%d\n",res);
                }
        }
    return 0;   
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值