【bzoj3514】【Codechef MARCH14 GERALD07加强版】【lct+主席树】

2024-02-20 15:32

本文主要是介绍【bzoj3514】【Codechef MARCH14 GERALD07加强版】【lct+主席树】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Description

N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。

Input

第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。

Output

 K行每行一个整数代表该组询问的联通块个数。

Sample Input

3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2

Sample Output

2
1
3
1

HINT

对于100%的数据,1≤N、M、K≤200,000。

题解:我们依次加入每条边。

           对于边i.

           如果i加入之后不会形成环就直接加进去。

           否则切开这个环上最早加入的边j,并记录p[i]=j表示i加入切开了j.

           这个数组显然可以用lct处理。

           对于每次询问,考虑l-r中每条边的贡献。

           可以发现如果p[i]<l则这条边的贡献是-1.

           因为这条边加入势必会将两个联通块接起来。

           所以我们只要统计出来l-r中p[i]<l的数量。然后用n减去这个数即可。

           这个可以用主席树来处理。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#define N 400010
using namespace std;
int sz,c[N][2],st[N],fa[N],rev[N],v[N],ls[N*20],rs[N*20],root[N],sum[N*20];
int p[N],mn[N],q,kind,n,m,lastans,x,y;
struct use{int st,en;}e[N<<1];
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void updata(int x){int l=c[x][0],r=c[x][1];mn[x]=x;if (v[mn[l]]<v[mn[x]]) mn[x]=mn[l];if (v[mn[r]]<v[mn[x]]) mn[x]=mn[r];
}
void pushdown(int x){int l=c[x][0],r=c[x][1];if (rev[x]){rev[l]^=1;rev[r]^=1;rev[x]^=1;swap(c[x][0],c[x][1]);}
}
void rotata(int x){int y=fa[x],z=fa[y],l,r;if (c[y][0]==x) l=0;else l=1;r=l^1;if (!isroot(y)){if (c[z][0]==y)c[z][0]=x;else c[z][1]=x;}fa[x]=z;fa[y]=x;fa[c[x][r]]=y;c[y][l]=c[x][r];c[x][r]=y;updata(y);updata(x);
}
void splay(int x){int top(0);st[++top]=x;for (int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];for (int i=top;i;i--) pushdown(st[i]);while (!isroot(x)){int y=fa[x],z=fa[y];if (!isroot(y)){if (c[y][0]==x^c[z][0]==y) rotata(x);else rotata(y);} rotata(x);}
}
void access(int x){int t(0);while (x){splay(x);c[x][1]=t;t=x;updata(x);x=fa[x];}}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
void link(int x,int y){makeroot(x);fa[x]=y;}
void cut(int x,int y){makeroot(x);access(y);splay(y);c[y][0]=fa[x]=0;}
int que(int x,int y){makeroot(y);access(x);splay(x);return mn[x];}
int find(int x){access(x);splay(x);int y=x;while (c[y][0]) y=c[y][0];return y;
}
void add(int l,int r,int last,int &y,int x){y=++sz;sum[y]=sum[last]+1;if (l==r) return;ls[y]=ls[last];rs[y]=rs[last];int mid=(l+r)>>1;if (x<=mid) add(l,mid,ls[last],ls[y],x);else add(mid+1,r,rs[last],rs[y],x);
}
int query(int l,int r,int x,int y,int val){if(r==val)return sum[y]-sum[x];int mid=(l+r)>>1;if(val<=mid)return query(l,mid,ls[x],ls[y],val);else return sum[ls[y]]-sum[ls[x]]+query(mid+1,r,rs[x],rs[y],val);
}
void pre(){int num=n;for (int i=1;i<=m;i++){int x=e[i].st,y=e[i].en;if (x==y) {p[i]=i;continue;} if (find(x)==find(y)){int u=que(x,y),t=v[u];p[i]=t;cut(e[t].st,u);cut(e[t].en,u);}v[++num]=i;mn[num]=num;link(x,num);link(y,num);}for (int i=1;i<=m;i++)add(0,m,root[i-1],root[i],p[i]);
}
void solve(int x,int y){if (kind==1) x^=lastans,y^=lastans;lastans=n-query(0,m,root[x-1],root[y],x-1);printf("%d\n",lastans);
}
int main(){memset(v,127/3,sizeof(v));scanf("%d%d%d%d",&n,&m,&q,&kind);for (int i=1;i<=n+m;i++) mn[i]=i;for (int i=1;i<=m;i++)scanf("%d%d",&e[i].st,&e[i].en);pre();  for (int i=1;i<=q;i++){scanf("%d%d",&x,&y);solve(x,y);  }
}


这篇关于【bzoj3514】【Codechef MARCH14 GERALD07加强版】【lct+主席树】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/728672

相关文章

【POJ】2104 K-th Number 静态第K小——主席树

传送门:【POJ】2104 K-th Number 题目分析: 哇咔咔,又get了一个新技能——主席树,初步学习主席树,一次AC,感觉好棒~ 也在此Orz一下发明者主席——fotile96,在叉姐群经常看到主席的身影,不过蒟蒻也只能仰望神犇的背影了,起步迟且天赋不如人,只能慢慢的走下去,希望有一天能看到另一个世界。 主席树的编程方式是函数式编程(可持久化),保证我们可以查询历史

【codechef】 Prime Distance On Tree【求树上路经长度为i的路径条数】【点分治+FFT】

传送门:【codechef】 Prime Distance On Tree 点分治+FFT水题……竟然n*n爆int没发现…… 而且NTT TLE,FFT跑的超级快…… my  code: my~~code: #include <bits/stdc++.h>using namespace std ;typedef long long LL ;#define clr( a , x ) m

【HDU】5333 Undirected Graph【LCT+BIT】

传送门:【HDU】5333 Undirected Graph my  code: my~~code: #pragma comment(linker, "/STACK:1024000000")#include <stdio.h>#include <string.h>#include <map>#include <algorithm>using namespace std ;typed

P4842 城市旅行(拆贡献 + LCT)

https://www.luogu.com.cn/problem/P4842 发现题目就是要维护一个LCT,然后我们只要把pushup写成功了就行。 那我们现在就不管LCT了,就单纯想用一棵二叉查找树怎么维护。分母是好搞的,分子我们要想点办法。 考虑右子树对左子树的贡献,我们假设处理出一个 L [ k ] L[k] L[k] 表示左子树中每个值乘以左边界的可选数量,我们现在再乘上右子树的大

18041 分期还款(加强版)

### 自查思路 1. 检查输入数据的处理是否正确。 2. 检查判断条件 `p <= d * r` 是否正确。 3. 确认公式计算和输出格式是否正确。 ### 伪代码 1. 读取输入的贷款金额、每月还款额和月利率。 2. 判断是否可以还清贷款:    - 如果每月还款额小于贷款金额乘以月利率,则输出“God”。    - 否则,计算还清贷款所需的月份数:      - 使用公式 m = lo

IOI2000 邮局 加强版 题解

[IOI2000] 邮局 加强版 题解 考虑动态规划,设 f i , j f_{i,j} fi,j​ 为经过了 i i i 个村庄,正在建第 j j j​ 个邮局的最优距离。 以及 w i , j w_{i,j} wi,j​ 表示区间 [ i , j ] [i,j] [i,j]​ 内建一个邮局时的距离总和。 a a a 数组表示每个村庄的坐标编号。 朴素版状态转移方程: f

spoj3267 D-query 主席树(可持久化线段树)

题目链接 题意:给n个数,m次查询,求[l,r]之间不重复数的个数。 思路:主席树。用一个map记录每个值在当前操作下最新的位置,从前往后插入主席树。对于查询[l,r],窝们在root[ l ]下查询在r之前的不重复数的个数。详见代码: /*********************************************************file name: spoj3267.

Codechef Sam and Sequences(单调队列)

题目链接:http://www.codechef.com/problems/PRYS03/ 这题只要考虑每个数字,最左和最右分别能延伸到的位置,然后就能计算出每个数字需要计算的次数,由于数字可能重复,所以对于左边维护到不大于的第一个数字位置,右边维护到小于的第一个数字位置,然后维护好后,在扫一遍计算总和即可 代码: #include <cstdio>#include <cstring>

Android面试题总结加强版(二)

http://blog.csdn.net/superjunjin/article/details/7855995 16.Android常用控件的信息 单选框(RadioButton与RadioGroup): RadioGroup用于对单选框进行分组,相同组内的单选框只有一个单选框被选中。 事件:setOnCheckedChangeListener(),处理单选框被选择

Android之面试题总结加强版(一)

转载:http://blog.csdn.net/itachi85/article/details/7426451 自己总结的最强android应用面试题集 1.activity的生命周期。 方法 描述 可被杀死 下一个 onCreate() 在activity第一次被创建的时候调用。这里是你做所有初始化设置的地方──创建视图、绑定数据至列表等。如果曾经有状态记