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 ...
随机推荐
- 文件夹进行MD5校验的实现算法
每份相同数据(文件夹)都可以生成一份唯一的md5校验文件,我们可以通过直接校验整个数据文件夹的方法来确定数据是否有误. 1.针对整个文件夹生成md5校验文件方法: 以data文件夹为例,我们需要得到d ...
- Android 4.4 (KitKat) SMS Apis Change——Android 4.4的一个重大变化
Android团队通过Android开发博客透漏今年会放出Android 4.4 (KitKat) ,同时更新了 SMS 的部分API.博客上讲只有default SMS app才能对短信数据库有写权 ...
- OpenvSwitch自动化重新编译和安装
相信使用过OpenvSwitch的人都知道,OpenvSwitch因为要替换一部分linux内核,所以在修改OpenvSwitch源码的时候,每次都需要重新编译和安装,这个过程十分的机械和枯燥,所以写 ...
- Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded.
EF6进行Insert操作的时候提示错误 Store update, insert, or delete statement affected an unexpected number of rows ...
- SVN上新增一个项目和用户
author:headsen chen date:2018-05-04 11:01:08 1,在SVN服务器上,打开SVN的软件,在项目里新建一个文件夹.在Repositories下面 2,use ...
- 【BZOJ4711】小奇挖矿 树形DP
[BZOJ4711]小奇挖矿 Description [题目背景] 小奇在喵星系使用了无限非概率驱动的采矿机,以至于在所有星球上都采出了一些矿石,现在它准备建一些矿石仓库并把矿石运到各个仓库里. [问 ...
- 12.php中无比坑爹的构造函数。
当你在php类中,写一个构造方法时,记得,一定要用__这是两个下划线,而不是一个.......... <?php class Car { // function _construct() { / ...
- document.cookie = 'wcookie_date=' + wv + ';max-age=60'
js cookie生命周期
- 2015-03-22——js常用的Array方法
Array array.concat(item...); //产生一个新数组如果item,是一个数组,那么它的每个元素会被分别添加(浅复制,只解析一层).示例:var a = [1, 3, 4];v ...
- LinkedList基本用法
https://blog.csdn.net/i_lovefish/article/details/8042883