[CTSC2008]网络管理 [整体二分]

题面

bzoj
luogu

所有事件按时间排序
按值划分下放

把每一个修改
改成一个删除一个插入

对于一个查询
直接查这个段区间有多少合法点
如果查询值大于等于目标值 进入左区间

如果一个查询无解
那么它要求第k大无解
k > 路径长 用lca维护即可

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#define Sqr(x) ((x)*(x))
using namespace std;
const int N = 8e4 + 5;
const int inf = 1e8 + 5;
struct Edge{
    int v, next;
}edge[N << 1];
int head[N], esize;
inline void addedge(int x, int y){
    edge[++esize] = (Edge){y, head[x]};
    head[x] = esize;
}
struct Node{
    int t, x, y, w, d;
    bool type;  //0是插入 1是查询
}node[N << 2], p1[N << 2], p2[N << 2];
int n, m, nsize, a[N], ans[N];
int tim, dfn[N], top[N], son[N], fa[N], size[N], rf[N], dep[N];
bool flag[N];

struct BIT{
    int w[N];
    void ins(int x, int d){while(x <= n){w[x] += d; x += x & -x;}}
    int qry(int x){int res = 0; while(x){res += w[x]; x -= x & -x;} return res;}
}bit;

inline void addnode(int x1, int x2, int x3, int x4, int x5, bool x6){
    ++nsize, node[nsize].t = x1, node[nsize].x = x2, node[nsize].y = x3,
    node[nsize].w = x4, node[nsize].d = x5, node[nsize].type = x6;
}

void dfs1(int x, int ff){
    dep[x] = dep[ff] + 1, size[x] = 1, fa[x] = ff;
    for(int i = head[x], vv; ~i; i = edge[i].next){
        vv = edge[i].v; if(vv == ff) continue;
        dfs1(vv, x);
        size[x] += size[vv];
        if(size[son[x]] < size[vv]) son[x] = vv;
    }
}

void dfs2(int x, int tp){
    top[x] = tp, dfn[x] = ++tim, rf[tim] = x;
    if(son[x]) dfs2(son[x], tp); else return;
    for(int i = head[x], vv; ~i; i = edge[i].next){
        vv = edge[i].v; if(vv == fa[x] || vv == son[x]) continue;
        dfs2(vv, vv);
    }
}

int LCA(int x, int y){
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        x = fa[top[x]];
    }
    return dep[x] < dep[y] ? x : y;
}

int qry(int x, int y){
    int res = 0;
    while(top[x] != top[y]){
        if(dep[top[x]] < dep[top[y]]) swap(x, y);
        res += bit.qry(dfn[x]) - bit.qry(dfn[top[x]] - 1);
        x = fa[top[x]];
    }
    if(dep[x] < dep[y]) swap(x, y); res += bit.qry(dfn[x]) - bit.qry(dfn[y] - 1);
    return res;
}

void erfn(int L, int R, int l, int r){
    if(L > R) return;
    if(l == r){
        for(int i = L; i <= R; ++i)
            if(node[i].type && ~ans[node[i].t]) ans[node[i].t] = l;
        return ;
    }
    int mid = l + ((r - l) >> 1);
    int t1 = 0, t2 = 0;
    for(int i = L; i <= R; ++i){
        if(node[i].type) {
            int cnt = qry(node[i].x, node[i].y);
            if(cnt >= node[i].w) p2[++t2] = node[i];
            else node[i].w -= cnt, p1[++t1] = node[i];//第k大!!先减再复制!!
        }
        else {
            if(node[i].w <= mid) p1[++t1] = node[i];
            else p2[++t2] = node[i], bit.ins(dfn[node[i].x], node[i].d);
        }
    }
    for(int i = L; i <= R; ++i)
        if(!node[i].type && node[i].w > mid)
            bit.ins(dfn[node[i].x], -node[i].d);
    for(int i = 1; i <= t1; ++i) node[L + i - 1] = p1[i];
    for(int i = 1; i <= t2; ++i) node[L + t1 + i - 1] = p2[i];
    erfn(L, L + t1 - 1, l, mid); erfn(L + t1, R, mid + 1, r);
}

int main() {
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &a[i]);
        addnode(0, i, 0, a[i], 1, 0);
    }
    for(int i = 1, x, y; i < n; ++i){
        scanf("%d%d", &x, &y);
        addedge(x, y); addedge(y, x);
    } dfs1(1, 0); dfs2(1, 1);
    for(int i = 1, x, y, z; i <= m; ++i){
        scanf("%d%d%d", &x, &y, &z); flag[i] = (bool)x;
        if(x){
            int len = dep[y] + dep[z] - 2 * dep[LCA(y, z)] + 1;
            if(x > len) ans[i] = -1;
            else addnode(i, y, z, x, 0, 1);
        }
        else addnode(i, y, 0, a[y], -1, 0), addnode(i, y, 0, z, 1, 0), a[y] = z, ans[i] = -1;
    }
    erfn(1, nsize, 0, inf);
    for(int i = 1; i <= m; ++i)
        if(flag[i]){
            if(ans[i] == -1) printf("invalid request!\n");
            else printf("%d\n", ans[i]);
        }
    //system("PAUSE");
    return 0;
}

原文地址:https://www.cnblogs.com/hjmmm/p/10658258.html

时间: 2024-08-23 14:54:14

[CTSC2008]网络管理 [整体二分]的相关文章

【BZOJ1146】【CTSC2008】网络管理 [整体二分]

网络管理 Time Limit: 50 Sec  Memory Limit: 162 MB[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门. 为了让分布在世界各地的N个部门之间协同工作,公司搭建了一个连接整个公司的通信网络. 该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,部门局域网内的所有机器都联向这个路由器,然后再通过这个通信子网与其他部门进行通信联络. 该网络结

[CTSC2008]网络管理(整体二分+树剖+树状数组)

一道经典的带修改树链第 \(k\) 大的问题. 我只想出三个 \(\log\) 的解法... 整体二分+树剖+树状数组. 那不是暴力随便踩的吗??? 不过跑得挺快的. \(Code\ Below:\) // luogu-judger-enable-o2 #include <bits/stdc++.h> #define lowbit(x) ((x)&(-(x))) using namespace std; const int maxn=80000+10; const int lim=1e

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要

bzoj 1146 网络管理Network (CDQ 整体二分 + 树刨)

题目传送门 题意:求树上路径可修改的第k大值是多少. 题解:CDQ整体二分+树刨. 每一个位置上的数都会有一段持续区间 根据CDQ拆的思维,可以将这个数拆成出现的时间点和消失的时间点. 然后通过整体二分第k大思路 + 树炮询问路径上出现点的个数就好了. 说一下整体二分的思路. 先假设第k大的值是mid, 然后按照时间顺序,出现一个数<=mid标记这个数的位置为1, 消失一个数<=mid,标记这个数的位置为0. 然后对于询问来说,询问路径上的值, 与 k进行比较, 如果 值 >= k则说明

BZOJ 1146: [CTSC2008]网络管理Network

1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3539  Solved: 1054[Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条高速光缆组成. 每个部门都有一个专属的路由器,

CDQ分治与整体二分小结

前言 这是一波强行总结. 下面是一波瞎比比. 这几天做了几道CDQ/整体二分,感觉自己做题速度好慢啊. 很多很显然的东西都看不出来 分治分不出来 打不出来 调不对 上午下午晚上的效率完全不一样啊. 完蛋.jpg 绝望.jpg. 关于CDQ分治 CDQ分治,求的是三维偏序问题都知道的. 求法呢,就是在分治外面先把一维变成有序 然后分治下去,左边(l,mid)关于右边(mid+1,r)就不存在某一维的逆序了,所以只有两维偏序了. 这个时候来一波"树状数组求逆序对"的操作搞一下二维偏序 就可

BZOJ 3110: [Zjoi2013]K大数查询 [整体二分]

有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. N,M<=50000,N,M<=50000a<=b<=N1操作中abs(c)<=N2操作中c<=Maxlongint 之前用树套树抄过一次...然而我并不适合写那玩意儿... 加上时间序的整体二分 普通的整体二分先处理了所有$[l,mid]$的影响因子在计算询问的答案来分组

bzoj1146整体二分+树链剖分+树状数组

其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 inline int read() 7 { 8 int x=0,f=1,ch=getchar(); 9 while(ch<

(困难) CF 484E Sign on Fence,整体二分+线段树

Bizon the Champion has recently finished painting his wood fence. The fence consists of a sequence of n panels of 1 meter width and of arbitrary height. The i-th panel's height is hi meters. The adjacent planks follow without a gap between them. Afte