[XXI Open Cup. Grand Prix of Korea]Chemistry
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[XXI Open Cup. Grand Prix of Korea]Chemistry相关的知识,希望对你有一定的参考价值。
Chemistry
题解
首先,我们考虑一条链拥有怎样的性质,也就是说我们如果要能确定我们当前的图是一条链,它有哪些必须满足的条件。
- 无环。
- 没有度数大于 2 2 2的点。
- 点数 − - −边数 = 1 =1 =1
对于条件
1
1
1与条件
2
2
2,很明显,对于一个固定的左端点,它肯定存在一个右端点使得这两点之间的区间都是满足条件的,而区间外都是不满足条件的。
也就是说满足条件的区间是连续的,这明显是可以通过双指针来进行维护的。
当然,维护这段区间显然是需要维护上面的两个条件是否满足是必须维护的。
对于条件
2
2
2,直接记录下来点的度数就行了,而条件
1
1
1,可以通过
L
C
T
LCT
LCT来进行维护。
既然我们已经知道了对于每个左端点,我们满足条件
1
,
2
1,2
1,2的区间,我们显然只需要在这个区间内找到有多少个点满足条件
3
3
3。
很明显,在条件
1
,
2
1,2
1,2的限制下,我们该图的边数最多也不会超过点数
−
1
-1
−1,所以满足条件
3
3
3也就是点数
−
-
−边数取到最小值
1
1
1的点的个数。
而点数
−
-
−边数这一个量是可以通过线段树来进行维护的。
我们往移动
l
l
l时相当于全局
−
1
-1
−1,而加边与删边都相当于对较大的一个端点当
n
n
n的区间内
∓
1
\\mp 1
∓1,由与只有右端点在这个范围内时才能够覆盖这条边。
对于每个左端点,我们都查询一下它的合法连续段中有多少个点取到最小值
1
1
1即可,线段树上也就只需要维护最小值与取到最小值的点的个数。
时间复杂度 O ( n log n ) O\\left(n\\log\\,n\\right) O(nlogn)。
源码
注意 L C T LCT LCT得多旋几次,保证均摊的复杂度。
#include<bits/stdc++.h>
using namespace std;
#define MAXN 250005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int mo=998244353;
const int inv2=499122177;
const int jzm=2333;
const int n1=50;
const int zero=10000;
const int orG=3,invG=332748118;
const double Pi=acos(-1.0);
const double eps=1e-5;
typedef pair<LL,int> pii;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
void print(_T x){putchar('\\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
LL gcd(LL a,LL b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1LL)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1LL;}return t;}
class Link_Cut_Tree{
private:
int father[MAXN],ch[MAXN][2],tot,sta[MAXN],stak;bool rev[MAXN];
inline void downdata(int x){
if(!rev[x])return ;swap(ch[x][0],ch[x][1]);
rev[x]=0;rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
}
inline bool identify(int x){return ch[father[x]][1]==x;}
inline bool isRoot(int x){return (ch[father[x]][0]^x)&&(ch[father[x]][1]^x);}
inline void connect(int x,int fa,int d){father[x]=fa;ch[fa][d]=x;}
inline void rotate(int x){
int y=father[x],z=father[y];
int d1=identify(y),d2=identify(x);
int B=ch[x][d2^1];father[x]=z;
if(!isRoot(y))connect(x,z,d1);
connect(B,y,d2);connect(y,x,d2^1);
}
inline void splay(int x){
int y=x;sta[stak=1]=x;while(!isRoot(y))sta[++stak]=y=father[y];
while(stak)downdata(sta[stak--]);
for(int y=father[x];!isRoot(x);rotate(x),y=father[x])
if(!isRoot(y))rotate(identify(x)==identify(y)?y:x);
}
inline void access(int x){for(int y=0;x;x=father[y=x])splay(x),ch[x][1]=y;}
inline void makeRoot(int x){access(x);splay(x);rev[x]^=1;}
inline int findRoot(int x){
access(x);splay(x);downdata(x);
while(ch[x][0])downdata(x=ch[x][0]);
return x;
}
public:
bool linkTree(int u,int v){
makeRoot(u);if(findRoot(v)==u)return 0;
father[u]=v;makeRoot(u);return 1;
}
void cutTree(int u,int v){
makeRoot(u);
if(findRoot(v)^u||father[u]^v||ch[v][0]^u||ch[u][1])return ;
father[u]=ch[v][0]=0;
}
}T;
class SegmentTree{
private:
int minn[MAXN<<2],mink[MAXN<<2],lzy[MAXN<<2];
void pushup(int rt){
minn[rt]=min(minn[lson],minn[rson]);mink[rt]=0;
if(minn[rt]==minn[lson])mink[rt]+=mink[lson];
if(minn[rt]==minn[rson])mink[rt]+=mink[rson];
}
void pushdown(int rt){
if(!lzy[rt])return ;
minn[lson]+=lzy[rt];lzy[lson]+=lzy[rt];
minn[rson]+=lzy[rt];lzy[rson]+=lzy[rt];
lzy[rt]=0;
}
public:
void build(int rt,int l,int r){
if(l==r){minn[rt]=l;mink[rt]=1;return ;}int mid=l+r>>1;
build(lson,l,mid);build(rson,mid+1,r);pushup(rt);
}
void modify(int rt,int l,int r,int al,int ar,int aw){
if(l>r||l>ar||r<al||al>ar)return ;
if(al<=l&&r<=ar){minn[rt]+=aw;lzy[rt]+=aw;return ;}
int mid=l+r>>1;pushdown(rt);
if(al<=mid)modify(lson,l,mid,al,ar,aw);
if(ar>mid)modify(rson,mid+1,r,al,ar,aw);
pushup(rt);
}
int query(int rt,int l,int r,int al,int ar){
if(l>r||l>ar||r<al||al>ar)return 0;int mid=l+r>>1,res=0;
if(al<=l&&r<=ar)return (minn[rt]==1)*mink[rt];pushdown(rt);
if(al<=mid)res+=query(lson,l,mid,al,ar);
if(ar>mid)res+=query(rson,mid+1,r,al,ar);
return res;
}
}S;
int n,m,deg[MAXN],head[MAXN],cur[MAXN],tot;LL ans;
map<int,bool>mp;
struct edge{int to,nxt;}e[MAXN<<1];
void addEdge(int u,int v){e[++tot]=(edge){v,head[u]};head[u]=tot;}
signed main(){
read(n);read(m);
for(int i=1,u,v;i<=m;i++)read[XXI Open Cup,Grand Prix of Tokyo]Ascending Matrix
2019-2020 XX Open Cup, Grand Prix of Korea
XX Open Cup, Grand Prix of Tokyo
2015-2016 XVI Open Cup, Grand Prix of Bashkortostan, SKB Kontur Cup Stage 2
XVIII Open Cup named after E.V. Pankratiev. Grand Prix of Peterhof.
XVII Open Cup named after E.V. Pankratiev. Eastern Grand Prix. Problem F. Buddy Numbers 贪心数论构造