省选测试5

A. 点点的圈圈

可以想到建出一颗树然后树形 \(dp\)

关键在于建树

根据题目给出的无交的条件,可以知道在圆的相对位置不变

用扫描线从左扫到右

再把圆拆成上半圆和下半圆

可以根据 \((x-x_i)^2+(y-y_i)^2=r_i^2\) 和是哪半圆 \(O(1)\) 计算出给定 \(x\)\(y\) 的值

于是用 \(set\) 维护一下圆就行,以 \(y\) 值递增排序

在插入时找到下半圆的前驱

如果没有前驱则说明是一个根

前驱是下半圆说明前驱是他的父亲

前驱是上半圆说明他和前驱是同一个父亲

最后再 \(dp\) 一遍就行

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,x,p,rt;
int f[100010],fa[100010];
int head[100010],ver[100010],to[100010],tot;
struct Circle{int x,y,r,w;}L[100010];
inline int q2(int x){return x*x;}
inline void add(int x,int y){
	//printf("%lld -> %lld\n",x,y);
	ver[++tot]=y;to[tot]=head[x];head[x]=tot;
}
inline double calcy(int id,int op){
	double w=sqrt(1.0*q2(L[id].r)-1.0*q2(L[id].x-x));
	return L[id].y+op*w;
}
void dfs(int x){
	int sum=0;
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];
		dfs(y);sum+=f[y];
	}
	f[x]=max(sum,L[x].w);
}
struct SL{
	int id,pos,op;//1加0删
	inline bool operator<(const SL &b)const{
		if(pos!=b.pos) return pos<b.pos;
		return op>b.op;
	}
}LL[200010];
struct node{
	int id,op;//1上-1下
	inline bool operator<(const node &b)const{
		double y=calcy(id,op),by=calcy(b.id,b.op);
		if(y!=by) return y<by;
		if(op!=b.op) return op>b.op;
		return id<b.id;
	}
};
set<node>S;
set<node>::iterator iter;
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	n=read();rt=n+1;
	for(int i=1;i<=n;i++) L[i].x=read(),L[i].y=read(),L[i].r=read(),L[i].w=read();
	for(int i=1;i<=n;i++){
		p++;LL[p].id=i;LL[p].pos=L[i].x-L[i].r+1;LL[p].op=1;
		p++;LL[p].id=i;LL[p].pos=L[i].x+L[i].r-1;LL[p].op=0;
	}
	sort(LL+1,LL+1+p);
	for(int i=1;i<=p;i++){
		x=LL[i].pos;
		if(LL[i].op==0){
			S.erase(S.find((node){LL[i].id,1}));
			S.erase(S.find((node){LL[i].id,-1}));
		}else{
			S.insert((node){LL[i].id,1});
			S.insert((node){LL[i].id,-1});
			iter=S.find((node){LL[i].id,-1});
			if(iter==S.begin()){
				add(rt,LL[i].id);fa[LL[i].id]=rt;
				continue;
			}
			iter--;
			if(iter->op==1){
				add(fa[iter->id],LL[i].id);fa[LL[i].id]=fa[iter->id];
			}else{
				add(iter->id,LL[i].id);fa[LL[i].id]=iter->id;
			}
		}
	}
	dfs(rt);
	printf("%lld\n",f[rt]);
	return 0;
}

B. 点点的计算

打出表,发现每一行的值都是杨辉三角乘上了一个系数

根据组合数同行递推式和乘上的系数,简单意会可得第 \(n\) 行的前 \(k\) 个的 \(LCM\)

就是 \(N...N-K+1\)\(LCM\)

那么考虑如何求出 \(LCM\)

可以构造一个数组 \(\prod\limits_{i=n}^{n-k+1}D_{n,i}=LCM(n...n-k+1)\)

那么假设已经构造好了 \(D_{n-1}\) 那么如何转移到 \(D_n\)

如果直接在 \(D_{n,n}\) 处插入 \(n\) 那么显然会多乘

于是找到他的每个质因数出现的位置,在那些位置都除掉相应的次数就行

可以用线段树维护,再可持久化一下就能在线了

Code
#include<bits/stdc++.h>
//#define int long long
#define rint signed
#define lson t[x].ls
#define rson t[x].rs
#define mod 1000000007
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int q,n,K,A,B,MOD,lst;
int prime[100010],id[100010],g[100010],cnt;
int C[200010],D[200010];
rint rt[100010],tot;
bool is[100010];
vector<pair<int,int>> vec[10010];
struct Seg{rint ls,rs;int prod;}t[10900000];
inline void init(int N){
	for(int i=2;i<=N;i++){
		if(!is[i]){prime[++cnt]=i;id[i]=cnt;g[i]=i;}
		for(int j=1;j<=cnt&&i*prime[j]<=N;j++){
			is[i*prime[j]]=1,g[i*prime[j]]=prime[j];
			if(i%prime[j]==0) break;
		}
	}
}
inline int qpow(int x,int k){
	int res=1,base=x;
	while(k){if(k&1) res=1ll*res*base%mod;base=1ll*base*base%mod;k>>=1;}
	return res;
}
void build(rint &x,int l,int r){
	t[x=++tot].prod=1;
	if(l==r) return ;
	int mid=(l+r)>>1;
	build(lson,l,mid);
	build(rson,mid+1,r);
}
void upd(rint &x,int l,int r,int pos,int k){
	rint pre=x;x=++tot;t[x]=t[pre];t[x].prod=1ll*t[pre].prod*k%mod;
	//printf("x : %d l : %lld r : %lld pos : %lld k : %lld\n",x,l,r,pos,k);
	//printf("t[pre].prod : %lld t[x].prod : %lld\n",t[pre].prod,t[x].prod);
	if(l==r) return ;
	int mid=(l+r)>>1;
	if(pos<=mid) upd(lson,l,mid,pos,k);
	else upd(rson,mid+1,r,pos,k);
}
int query(rint x,int l,int r,int L,int R){
	if(L<=l&&r<=R) return t[x].prod;
	int mid=(l+r)>>1,res=1;
	if(L<=mid) res=1ll*res*query(lson,l,mid,L,R)%mod;
	if(R>mid) res=1ll*res*query(rson,mid+1,r,L,R)%mod;
	return res;
}
void print(rint x,int l,int r){
	printf("x : %d l : %lld r : %lld prod : %lld\n",x,l,r,t[x].prod);
	if(l==r) return ;
	int mid=(l+r)>>1;
	print(lson,l,mid);
	print(rson,mid+1,r);
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	q=read()-1;
	n=read(),K=read();
	A=read(),B=read(),MOD=read();init(100000);
	for(int i=1;i<=q;i++) C[i]=read();
	for(int i=1;i<=q;i++) D[i]=read();
	t[0].prod=1;
	for(int i=1,x,p,k,kkk;i<=100000;i++){
		x=i;rt[i]=rt[i-1];
		while(x!=1){
			p=g[x];k=0;
			while(x%p==0) x/=p,k++;kkk=k;
			upd(rt[i],1,100000,i,qpow(p,k));
			for(int j=(int)vec[id[p]].size()-1,pos,kk;j>=0;j--){
				pos=vec[id[p]][j].first,kk=vec[id[p]][j].second;
				if(kk>=k){
					upd(rt[i],1,100000,pos,qpow(qpow(p,k),mod-2));
					vec[id[p]][j].second-=k;if(!vec[id[p]][j].second) vec[id[p]].pop_back();
					break;
				}else{
					k-=kk;
					upd(rt[i],1,100000,pos,qpow(qpow(p,kk),mod-2));
					vec[id[p]].pop_back();
				}
			}
			vec[id[p]].push_back(make_pair(i,kkk));
		}
	}
	printf("%d\n",lst=query(rt[n],1,100000,n-K+1,n));
	for(int i=1;i<=q;i++){
		n=1ll*(1ll*A*lst+C[i])%MOD+1;
		K=1ll*(1ll*B*lst+D[i])%n+1;
		printf("%d\n",lst=query(rt[n],1,100000,n-K+1,n));
	}
	return 0;
}

C. 点点的最大流

树的情况是平凡的,那考虑把仙人掌边双缩点后变成树

对于每一个边双,都有两条路从进来的点走到出去的点

而且其中一定会走边权最小的边,那么我们把最小的边断掉

给剩下的每条边都加上这个边权,就相当于把两条路的流量都加起来了

\(LCT\) 维护,修改的时候分类讨论一下就行了

Code
#include<bits/stdc++.h>
#define int long long
#define rint signed
#define lson t[x].son[0]
#define rson t[x].son[1]
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
int n,m,q;
int head[300010],ver[600010],to[600010],tot;
int stk[300010],p;
int dfn[300010],low[300010],bl[300010],clo,col;
set<pair<int,int>> S[300010];
set<pair<int,int>>::iterator iter;
bool vis[300010];
struct node{int fa,son[2],mn,val,atag;bool rev;}t[300010];
struct Edge{int x,y,w;}e[300010];
inline void add(int x,int y){ver[++tot]=y;to[tot]=head[x];head[x]=tot;}
inline bool isrt(int x){return (t[t[x].fa].son[0]!=x)&&(t[t[x].fa].son[1]!=x);}
inline void pushup(int x){t[x].mn=min({t[lson].mn,t[rson].mn,t[x].val});}
inline void pushrev(int x){swap(lson,rson);t[x].rev^=1;}
inline void pushadd(int x,int k){t[x].atag+=k,t[x].val+=k,t[x].mn+=k;}
inline void pushdown(int x){
	if(t[x].rev) pushrev(lson),pushrev(rson),t[x].rev=0;
	if(t[x].atag) pushadd(lson,t[x].atag),pushadd(rson,t[x].atag),t[x].atag=0;
}
inline void rotate(int x){
	int y=t[x].fa;
	int z=t[y].fa;
	int k=t[y].son[1]==x;
	if(!isrt(y)) t[z].son[t[z].son[1]==y]=x;
	t[y].son[k]=t[x].son[k^1];
	t[t[x].son[k^1]].fa=y;
	t[x].son[k^1]=y;
	t[y].fa=x;t[x].fa=z;
	pushup(y);pushup(x);
}
inline void splay(int x){
	int y=x,z=0;stk[++z]=x;
	while(!isrt(y)) stk[++z]=y=t[y].fa;
	while(z) pushdown(stk[z--]);
	while(!isrt(x)){
		y=t[x].fa;z=t[y].fa;
		if(!isrt(y)) (t[z].son[0]==y)^(t[y].son[1]==x)?rotate(x):rotate(y);
		rotate(x);
	}
	pushup(x);
}
inline void access(int x){for(int y=0;x;x=t[y=x].fa) splay(x),t[x].son[1]=y,pushup(x);}
inline void makert(int x){access(x);splay(x);pushrev(x);}
inline int findrt(int x){access(x);splay(x);while(lson) x=lson;splay(x);return x;}
inline void split(int x,int y){makert(x);access(y);splay(y);}
inline void link(int x,int y){makert(x);t[x].fa=y;}
inline void cut(int x,int y){makert(x);access(y);splay(y);t[x].fa=t[y].son[0]=0;pushup(y);}
void tarjan(int x,int fa){
	dfn[x]=low[x]=++clo;stk[++p]=x;vis[x]=1;
	for(int i=head[x];i;i=to[i]){
		int y=ver[i];
		if(y==fa) continue;
		if(!dfn[y]){
			tarjan(y,x);
			low[x]=min(low[x],low[y]);
		}else if(vis[y]) low[x]=min(low[x],dfn[y]);
	}
	if(dfn[x]==low[x]){
		int k;col++;
		do{
			k=stk[p--];
			S[col].insert(make_pair(t[k].val,k));
			bl[k]=col;
			vis[k]=0;
		}while(k!=x);
	}
}
signed main(){
#ifdef LOCAL
	freopen("in","r",stdin);
	freopen("out","w",stdout);
#endif
	n=read(),m=read();
	for(int i=0;i<=n;i++) t[i].val=t[i].mn=inf;
	for(int i=n+1;i<=n+m;i++){
		e[i].x=read(),e[i].y=read(),e[i].w=read();
		t[i].val=t[i].mn=e[i].w;
		add(e[i].x,i);add(i,e[i].x);
		add(e[i].y,i);add(i,e[i].y);
	}
	tarjan(1,0);
	for(int i=1,v,x;i<=col;i++){
		if(S[i].size()==1){
			x=(*S[i].begin()).second;
			if(x>n) link(x,e[x].x),link(x,e[x].y);
		}else{
			iter=++S[i].begin();
			while(iter!=S[i].end()){
				x=(*iter).second;
				if(x>n) link(x,e[x].x),link(x,e[x].y);
				iter++;
			}
			x=(*S[i].begin()).second;
			split(e[x].x,e[x].y);
			t[e[x].y].val+=(*S[i].begin()).first;
			t[e[x].y].atag+=(*S[i].begin()).first;
		}
	}
	q=read();
	for(int i=1,op,x,y,a,b,xx,aa,bb;i<=q;i++){
		op=read(),x=read(),y=read();
		if(op==1){
			x+=n;
			if(S[bl[x]].size()==1){
				split(x,x);
				t[x].val=t[x].mn=y;
			}else if((*S[bl[x]].begin()).second==x){
				a=e[x].x,b=e[x].y;
				split(a,b);
				t[b].val-=((*S[bl[x]].begin()).first);
				t[b].atag-=((*S[bl[x]].begin()).first);
				//t[b].mn-=((*S[bl[x]].begin()).first);
				splay(x);t[x].val=y;
				splay(b);
				S[bl[x]].erase(S[bl[x]].begin());
				S[bl[x]].insert(make_pair(y,x));
				if((*S[bl[x]].begin()).second==x){
					t[b].val+=y;
					t[b].atag+=y;
					//t[b].mn+=y;
				}else{
					xx=(*S[bl[x]].begin()).second;
					aa=e[xx].x,bb=e[xx].y;
					cut(aa,xx);cut(xx,bb);
					link(x,a);link(x,b);
					split(aa,bb);
					t[bb].val+=(*S[bl[x]].begin()).first;
					//t[bb].mn+=(*S[bl[x]].begin()).first;
					t[bb].atag+=(*S[bl[x]].begin()).first;
				}
			}else{
				xx=(*S[bl[x]].begin()).second;
				aa=e[xx].x,bb=e[xx].y;a=e[x].x,b=e[x].y;
				split(aa,bb);
				t[bb].val-=(*S[bl[x]].begin()).first;
				t[bb].atag-=(*S[bl[x]].begin()).first;
				//t[bb].mn-=(*S[bl[x]].begin()).first;
				splay(x);
				S[bl[x]].erase(make_pair(t[x].val,x));
				S[bl[x]].insert(make_pair(y,x));
				t[x].val=y;
				splay(bb);
				if((*S[bl[x]].begin()).second==xx){
					//t[bb].mn+=(*S[bl[x]].begin()).first;
					t[bb].atag+=(*S[bl[x]].begin()).first;
					t[bb].val+=(*S[bl[x]].begin()).first;
				}else{
					cut(a,x);cut(x,b);
					link(aa,xx);link(bb,xx);
					split(a,b);
					t[b].val+=y;
					//t[b].mn+=y;
					t[b].atag+=y;
				}
			}
		}else{
			split(x,y);printf("%lld\n",t[y].mn);
		}
	}
	return 0;
}
posted @ 2022-01-21 20:42  Max_QAQ  阅读(42)  评论(0编辑  收藏  举报