并不对劲的bzoj4538:loj2049:p3250:[HNOI2016]网络
题意
有一棵\(n\)(\(n\leq 10^5\))个点的树,\(m\)(\(m\leq 2\times 10^5\))个操作。操作有三种:1.给出\(u,v,k\),表示加入一条从\(u\)到\(v\)权值为\(k\)的路径;2.给出\(k\),表示删除\(k\)时刻加入的路径;3.给出\(x\),表示询问不经过点\(x\)的路径的权值最大值。
题解
3操作看上去很奇怪,先假装它是“询问经过\(x\)的路径的权值最大值”。
这样1操作就可以看成区间修改为最大值,3操作可以看成单点求值。注意这是不用pushdown的,因为线段树中一个点的值应该是所有祖先的tag的最大值。
2操作是区间删一个数,那么可以在线段树的每个点维护一个可删堆,1操作变成向一个区间的点的堆中加一个数,2操作变成将一个区间的点的堆删一个数。
这样之所以是对的,是因为没有pushdown或pushup,使1操作时涉及的区间和对应的2操作涉及的区间是相同的,不会有堆被删空。
再考虑3操作。
这时1、2操作影响的区域就由“这条路径上的点”变成了“不在这条路径上的点”,需要手动处理出 在这条路径上的点的区间 的补集。
注意不能先将区间\([1,n]\)区间加数再将这条路径上的点的区间删数,因为“将区间\([1,n]\)区间加数”只会改线段树根节点的堆,而“将这条路径上的点的区间删数”会把某些点的堆大小删成负数。
代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
#define rep(i,x,y) for(int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];~k;k=nxt[k])
#define maxn 100007
#define maxm 200007
#define mp make_pair
#define fi first
#define se second
#define pb push_back
#define pii pair<int,int>
#define ls (u<<1)
#define rs (u<<1|1)
#define mi ((l+r)>>1)
#define fi first
#define se second
#define mp make_pair
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
char ch[20];int f=0;
if(!x){putchar('0'),putchar('\n');return;}
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
}
struct deadque
{
priority_queue<int>yes,no;
int top(){while(!no.empty()&&yes.top()==no.top())yes.pop(),no.pop();return yes.top();}
int size(){return yes.size()-no.size();}
void push(int x){return yes.push(x);}
void del(int x){return no.push(x);}
}q[maxn<<2];
int fir[maxn],nxt[maxm],v[maxm],cnte,qa[maxm],qb[maxm],qc[maxm];
int n,m,dep[maxn],son[maxn],fa[maxn],top[maxn],siz[maxn],dfn[maxn],tim,num;
pii b[maxn];
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void getson(int u)
{
siz[u]=1;
view(u,k)if(v[k]!=fa[u])
{
fa[v[k]]=u,dep[v[k]]=dep[u]+1,getson(v[k]),siz[u]+=siz[v[k]];
if(!son[u]||siz[son[u]]<siz[v[k]])son[u]=v[k];
}
}
void gettop(int u,int anc)
{
dfn[u]=++tim,top[u]=anc;
if(son[u])gettop(son[u],anc);
view(u,k)if(v[k]!=fa[u]&&v[k]!=son[u])gettop(v[k],v[k]);
}
void add(int u,int l,int r,int x,int y,int k,int f)
{
if(x<=l&&r<=y){if(f)q[u].push(k);else q[u].del(k);return;}
if(x<=mi)add(ls,l,mi,x,y,k,f);
if(y>mi)add(rs,mi+1,r,x,y,k,f);
}
int ask(int u,int l,int r,int x)
{
if(x<=l&&r<=x){return q[u].size()==0?-1:q[u].top();}
int res=q[u].size()==0?-1:q[u].top();
if(x<=mi)return max(res,ask(ls,l,mi,x));
return max(res,ask(rs,mi+1,r,x));
}
void addrd(int x,int y,int k,int f)
{
num=0;
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
num++,b[num]=mp(dfn[top[x]],dfn[x]),x=fa[top[x]];
}
if(dep[x]<dep[y])swap(x,y);
num++,b[num]=mp(dfn[y],dfn[x]);
int lst=1;
sort(b+1,b+num+1);
rep(i,1,num)
{
if(lst<=b[i].fi-1)add(1,1,n,lst,b[i].fi-1,k,f);
lst=b[i].se+1;
}
if(lst<=n)add(1,1,n,lst,n,k,f);
}
int main()
{
memset(fir,-1,sizeof(fir));
n=read(),m=read();
rep(i,1,n-1){int x=read(),y=read();ade(x,y),ade(y,x);}
getson(1),gettop(1,1);
rep(i,1,m)
{
int t=read();
if(t==0){qa[i]=read(),qb[i]=read(),qc[i]=read();addrd(qa[i],qb[i],qc[i],1);}
else if(t==1){int j=read();if(qa[j]==0)continue;addrd(qa[j],qb[j],qc[j],0);}
else{int x=read();write(ask(1,1,n,dfn[x]));}
}
return (0-0);
}
并不对劲的bzoj4538:loj2049:p3250:[HNOI2016]网络的更多相关文章
- P3250 [HNOI2016]网络
LINK:网络 一棵树 每次添加一条路径 或者删除之前的一条路径 或询问除了不经过某个点之外剩下的最大值. 一个显然的思路 对于一条路径的权值我们直接把权值塞上去 标记永久化一下即可. 考虑如何求答案 ...
- luogu P3250 [HNOI2016]网络
传送门 考虑只有一个询问,怎么使用暴力枚举最快的得到答案.因为要求最大的,所以可以把链按权值从大往小排序,然后往后扫,找到一个没有交的就是答案,直接退出 一堆询问,可以考虑整体二分,先二分一个值\(m ...
- 洛咕P3250 [HNOI2016]网络 整体二分
这题太神仙了必须写博客... 显然可以想到二分答案.二分一个答案mid,如果所有长度\(\geq mid\)的路径都过x,那么答案一定\(<mid\),否则答案\(\geq mid\). 那么就 ...
- [洛谷P3250][HNOI2016]网络
题目大意:给定一棵树.有三种操作: $0\;u\;v\;t:$在$u$到$v$的链上进行重要度为$t$的数据传输. $1\;x:$结束第$x$个数据传输. $2\;x:$询问不经过点$x$的数据传输中 ...
- 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)
传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...
- P3250 [HNOI2016] 网络 (树剖+堆/整体二分+树上差分+树状数组)
解法1: 本题有插入路径和删除路径,在每个节点维护插入堆和删除堆,查询时两者top一样则一直弹出.如果每个节点维护的是经过他的路径,显然有些不好处理,正难则反,每个点维护不经过他的路径,那么x节点出了 ...
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
[BZOJ4538][Hnoi2016]网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互 ...
- BZOJ 4538: [Hnoi2016]网络 [整体二分]
4538: [Hnoi2016]网络 题意:一棵树,支持添加一条u到v权值为k的路径,删除之前的一条路径,询问不经过点x的路径的最大权值 考虑二分 整体二分最大权值,如果\(k \in [mid+1, ...
- 【LG3250】[HNOI2016]网络
[LG3250][HNOI2016]网络 题面 洛谷 题解 30pts 对于\(m\leq 2000\),直接判断一下这个个点是否断掉一个交互,没断掉的里面取\(max\)即可,复杂度\(O(m^2\ ...
随机推荐
- redis快照关闭了导致不能持久化的问题
在使用redis的时候我们经常会遇到这种bug: Python与Redis交互时,设置数据出现下列报错信息: MISCONF Redis is configured to save RDB s ...
- 反省——关于csp-s模拟50
本人于搜索csp-s模拟49题解时,有意识地点开了一篇关于csp-s模拟50T2的题解,并知道了题解是二维前缀和以及四维偏序. 更重要的是,那篇博客说有解法二,叫二维莫队. 于是我上网搜索二维莫队,结 ...
- TCP学习
参考 https://coolshell.cn/articles/11564.html https://coolshell.cn/articles/11609.html
- Leetcode题目70.爬楼梯(动态规划+递归-简单)
题目描述: 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 1: 输入: 2 输出: 2 ...
- Qt子窗口QMidSubwindow全屏出现的问题总结
我的需求:想全屏一个子窗口QMidSubwindow,禁止显示最大化最小化和关闭按钮. 我开始尝试的是网上介绍的方法,把结果展现给大家一下,最后再总结: 方法1:QMidSubwindow直接调用sh ...
- ubuntu如何删除刚添加的源?
答: sudo add-apt-repository -r <source_url> 如: sudo add-apt-repository -r ppa:linaro-maintainer ...
- LC 820. Short Encoding of Words
Given a list of words, we may encode it by writing a reference string S and a list of indexes A. For ...
- 2.使用kubeadm快速搭建k8s集群
准备工作: 时间同步 systemctl stop iptables.servicesystemctl stop firewalld.service 安装docker wget https://mir ...
- docker 安装 jmeter
1.下载jmeterwget http://mirrors.tuna.tsinghua.edu.cn/apache//jmeter/binaries/apache-jmeter-5.1.1.tgz2. ...
- grep 正则表达式用引号括起来和元字符加反斜杠转义的测试
grep 正则表达式用引号括起来和元字符加反斜杠转义的测试 实验在 grep 命令中的表达式:不加引号,加单引号,加双引号的区别,以及部分元字符前加与不加 `\’ 进行转义的区别.实验环境为“实验楼( ...