Luogu-3250 [HNOI2016]网络
Luogu-3250 [HNOI2016]网络
题面
题解
CDQ分治...这个应该算是整体二分吧
二分重要度,按照时间从小到大加入大于重要度的边
对于一个询问,如果经过这个点的边数不等于加入的边数,那就说明有比重要度大而且不经过这个点的边,然后分成两部分继续做
看Candy?大佬的博客学会了一种加边方法:记录dfn序,对于一条边\(u\),\(v\)。让端点的\(cnt\)++,\(lca\)和\(fa[lca]\)的--,找经过一个点边数只需要查询他的子树大小就好啦
代码
#include<map>
#include<queue>
#include<cmath>
#include<ctime>
#include<stack>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline char gc(){
//static char buf[100000],*p1,*p2;
//return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
return getchar();
}
inline int read(){
int ans=0,fh=1;
char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') fh=-1; ch=gc();}
while(ch>='0'&&ch<='9') ans=(ans<<1)+(ans<<3)+ch-'0',ch=gc();
return ans*fh;
}
const int maxn=2e5+100,maxm=maxn<<1;
struct node{
int a,b,v;
}c[maxn];
int n,m,head[maxn],nex[maxm],v[maxm],num=1;
int tre[maxn],cr[maxn],cl;
int fa[maxn],top[maxn],siz[maxn],dep[maxn],son[maxn],dfn[maxn],tim;
int tmp1[maxn],tmp2[maxn],p[maxn],ans[maxn],mx,qtot;
void revise(int x,int z){
for(int i=x;i<maxn;i+=i&(-i))
if(cr[i]==cl) tre[i]+=z;
else cr[i]=cl,tre[i]=z;
}
int query(int x,int Ans=0){
for(int i=x;i;i-=i&(-i))
if(cr[i]==cl) Ans+=tre[i];
return Ans;
}
void add(int x,int y){
v[++num]=y;
nex[num]=head[x];
head[x]=num;
v[++num]=x;
nex[num]=head[y];
head[y]=num;
}
void dfs1(int x,int f,int dp){
fa[x]=f,dep[x]=dp,siz[x]=1;
for(int i=head[x];i;i=nex[i]){
int y=v[i];
if(y==f) continue;
dfs1(y,x,dp+1);
if(siz[y]>siz[son[x]])
son[x]=y;
siz[x]+=siz[y];
}
}
void dfs2(int x,int tp){
top[x]=tp,dfn[x]=++tim;
if(son[x]) dfs2(son[x],tp);
for(int i=head[x];i;i=nex[i])
if(v[i]!=fa[x]&&v[i]!=son[x])
dfs2(v[i],v[i]);
}
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;
}
void work(int x,int y,int z){
int lca=Lca(x,y);
revise(dfn[x],z),revise(dfn[y],z);
revise(dfn[lca],-z);if(lca!=1) revise(dfn[fa[lca]],-z);
}
int check(int x){
int l=dfn[x],r=dfn[x]+siz[x]-1;
return query(r)-query(l-1);
}
void cdq(int l,int r,int L,int R){
if(L>R) return;
if(l==r){
int ltot=0;cl++;
for(int i=L;i<=R;i++){
int x=p[i],z=c[x].v>0?1:-1;
if(~c[x].b) work(c[x].a,c[x].b,z),ltot+=z;
else if(check(c[x].a)!=ltot) ans[c[x].v]=l;
}
return;
}
int mid=l+r>>1;
int lc=0,rc=0,cnt=L-1,ltot=0;cl++;
for(int i=L;i<=R;i++){
int x=p[i],z=c[x].v>0?1:-1;
if(~c[x].b){
if(abs(c[x].v)>mid)
work(c[x].a,c[x].b,z),tmp2[++rc]=x,ltot+=z;
else tmp1[++lc]=x;
}
else{
int pp=check(c[x].a);
if(pp!=ltot) tmp2[++rc]=x;
else tmp1[++lc]=x;
}
}
for(int i=1;i<=lc;i++) p[++cnt]=tmp1[i];
for(int i=1;i<=rc;i++) p[++cnt]=tmp2[i];
cdq(l,mid,L,L+lc-1),cdq(mid+1,r,L+lc,R);
}
int main(){
// freopen("3250.in","r",stdin);
n=read(),m=read();
int x,y,ms,z;
for(int i=1;i<n;i++)
x=read(),y=read(),add(x,y);
dfs1(1,1,1);
dfs2(1,1);
for(int i=1;i<=m;i++){
ms=read(),p[i]=i;
if(!ms){
x=read(),y=read(),z=read();
c[i]=(node){x,y,z},mx=max(mx,z);
}
else{
x=read();
if(ms==1) c[i]=c[x],c[i].v*=-1;
else c[i].a=x,c[i].b=-1,c[i].v=++qtot;
}
}
memset(ans,-1,sizeof(ans));
cdq(1,mx,1,m);
for(int i=1;i<=qtot;i++)
printf("%d\n",ans[i]);
return 0;
}
Luogu-3250 [HNOI2016]网络的更多相关文章
- luogu P3250 [HNOI2016]网络
传送门 考虑只有一个询问,怎么使用暴力枚举最快的得到答案.因为要求最大的,所以可以把链按权值从大往小排序,然后往后扫,找到一个没有交的就是答案,直接退出 一堆询问,可以考虑整体二分,先二分一个值\(m ...
- 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\ ...
- 4538: [Hnoi2016]网络
4538: [Hnoi2016]网络 链接 分析: 整体二分. 对于一次操作,可以二分一个答案mid,判断权值大于mid的路径是否全部经过这个点.如果是 ,那么这次询问的答案在[l,mid-1]之间, ...
- [HNOI2016]网络 树链剖分,堆
[HNOI2016]网络 LG传送门 表示乱搞比正解难想. 整体二分很好想吧. 但是为了好写快乐,我们选择三个\(\log\)的乱搞. 先树剖,线段树套堆维护区间最大值.对于一次修改,如果是插入,就把 ...
- [Luogu 2604] ZJOI2010 网络扩容
[Luogu 2604] ZJOI2010 网络扩容 第一问直接最大流. 第二问,添加一遍带费用的边,边权 INF,超级源点连源点一条容量为 \(k\) 的边来限流,跑费用流. 大约是第一次用 nam ...
- 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组
[BZOJ4538][Hnoi2016]网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互 ...
- (BZOJ4538)HNOI2016 网络
HNOI2016 Day1 T2 网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互时,数 ...
- BZOJ 1834 Luogu P2604 [ZJOI2010]网络扩容 (最小费用最大流)
题目连接: (luogu) https://www.luogu.org/problemnew/show/P2604 (bzoj) https://www.lydsy.com/JudgeOnline/p ...
随机推荐
- django 之 常用命令
Django 基本命令 本节主要是为了让您了解一些django最基本的命令,请尝试着记住它们,并且多多练习下 1. 新建一个 django project django-admin.py startp ...
- Delphi StringReplace – 替换字符函数
Delphi StringReplace – 替换字符函数 Delphi中的StringReplace函数是SysUtils单元中自带的函数,该函数可以替换字符串中的指定字符. 1 2 3 4 5 6 ...
- 【BZOJ3673/3674】可持久化并查集/可持久化并查集加强版 可持久化线段树
[BZOJ3674]可持久化并查集加强版 Description Description:自从zkysb出了可持久化并查集后……hzwer:乱写能AC,暴力踩标程KuribohG:我不路径压缩就过了! ...
- delphi ---ttoolbar,ttoolbutton
1.button style:tbsButton,tbsCheck,tbsDivider,tbsDropDown,tbsSeparator,tbsTextButton tbsButton:普通的控件 ...
- REDO 的内容:改变向量
REDO 的内容 ---改变向量 redo的内容并不是sql语句,他是放的一些改变,叫改变向量. 数据库恢复的时候并不是执行sql语句,而是一个物理的过程,是一个数据块的覆盖.是改变数据块的大小. 可 ...
- js事件委托和jQuery事件绑定on , off , one , bind , unbind , die
一. 事件委托什么是事件委托?用现实中的理解就是:有100 个学生同时在某天中午收到快递,但这100 个学生不可能同时站在学校门口等,那么都会委托门卫去收取,然后再逐个交给学生.而在jQuery 中, ...
- caffe杂
一.finetune命令: mpirun /home/zhangsuosheng/caffe_mpi/build/tools/caffe train -solver solver.prototxt - ...
- Dictionary里使用struct,enum做key
首先看下Dictionary的源码 public void Add (TKey key, TValue value) { if (key == null) throw new ArgumentNull ...
- vue-cli注册全局组件
在main.js开头引入组件,然后注册组件,例如: import Vue from 'vue' import VueRouter from 'vue-router' import VueResourc ...
- 7.Insert Methods-官方文档摘录
总结 列举insert插入方法 MongoDB provides the following methods for inserting documents into a collection: db ...