把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

2019.7.11 义乌模拟赛 T3 C

首先我们考虑这个图的特殊性质。
显然这是个仙人掌树对吧。
我们可以圆方树。
然后就变成了两两方点之间距离,距离定义为2^方点数量。
这个东西线段树随便维护好吧。
就是拆成上下两段计算,上行是永久加入,下行是临时加入要撤销。
时间复杂度\(O(nlogn)\)
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define ll long long
#define db double
#define N 1000000
#define M 30
#define mod 19260817
#define eps (1e-7)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
using namespace std;
I void read(int &x){
	char s=Gc();x=0;while(s<'0'||s>'9') s=Gc();
	while(s>='0'&&s<='9') x=x*10+s-48,s=Gc();
}
int n,m,k,x[N+5<<1],y[N+5<<1],st[N+5],sh,fl[N+5],scc[N+5],dfn[N+5],dh,siz[N+5],bg[N+5];ll F[N+5<<2],Sum[N+5<<2],ans;const int inv=9630409;
struct yyy{int to,z;}tmp;
struct ljb{
	int head,h[N+5];yyy f[N+5<<2];
	I void add(int x,int y){f[++head]=(yyy){y,h[x]};h[x]=head;/*printf("%d %d\n",x,y);*/}
}s,G;
I void dfs(int x,int last){
	yyy tmp;if(fl[x]) {while(st[sh+1]^x) fl[st[sh]]=0,scc[st[sh--]]=x;return;}fl[x]=1;st[++sh]=x;
	for(int i=s.h[x];i;i=tmp.z) tmp=s.f[i],!scc[tmp.to]&&tmp.to^last&&(dfs(tmp.to,x),0);!scc[x]&&(scc[x]=-1);sh-=(st[sh]==x); 
}
I void Make(int x,int last){
	yyy tmp;dfn[++dh]=x;bg[x]=dh;siz[x]=1;for(int i=G.h[x];i;i=tmp.z) tmp=G.f[i],tmp.to^last&&(Make(tmp.to,x),siz[x]+=siz[tmp.to]);
}
I void Up(int now){Sum[now]=Sum[now<<1]+Sum[now<<1|1];}
I void pushF(int now){F[now]=F[now]*F[now>>1]%mod,Sum[now]=Sum[now]*F[now>>1]%mod;}
I void push(int now){if(F[now]==1) return;pushF(now<<1);pushF(now<<1|1);F[now]=1;}
I void build(int l=1,int r=n,int now=1){
	F[now]=1;if(l==r) return (void)(Sum[now]=(scc[dfn[l]]==dfn[l]));int m=l+r>>1;build(l,m,now<<1);build(m+1,r,now<<1|1);Up(now);
}
I void get(int x,int y,int z,int l=1,int r=n,int now=1){
	if(x<=l&&r<=y) {F[now]=F[now]*z%mod;Sum[now]=Sum[now]*z%mod;return;}push(now);int m=l+r>>1;x<=m&&(get(x,y,z,l,m,now<<1),0);y>m&&(get(x,y,z,m+1,r,now<<1|1),0);Up(now);
}
I ll find(int x,int y,int l=1,int r=n,int now=1){
	if(x<=l&&r<=y) return Sum[now];push(now);int m=l+r>>1,ans=0;x<=m&&(ans+=find(x,y,l,m,now<<1));y>m&&(ans+=find(x,y,m+1,r,now<<1|1));return ans%mod;
}
I void GetAns(int x,int last){
	~scc[x]&&bg[x]^1&&(ans+=find(1,bg[x]-1)%mod,get(1,bg[x]-1,2),0);/*printf(" %d %lld\n",x,ans);*/yyy tmp;for(int i=G.h[x];i;i=tmp.z) tmp=G.f[i],tmp.to^last&&(GetAns(tmp.to,x),0);
	~scc[last]&&(get(bg[x],bg[x]+siz[x]-1,2),0);~scc[x]&&bg[x]^1&&(get(1,bg[x]-1,inv),0);
}
I int Ch(int x){return ~scc[x]?scc[x]:x;}
int main(){
	freopen("c.in","r",stdin);freopen("c.out","w",stdout);
	re int i,j;scanf("%d%d",&n,&m);for(i=1;i<=m;i++)read(x[i]),read(y[i]),s.add(x[i],y[i]),s.add(y[i],x[i]);dfs(1,0);//printf("\n");
	for(i=1;i<=m;i++) Ch(x[i])^Ch(y[i])&&(G.add(Ch(x[i]),Ch(y[i])),G.add(Ch(y[i]),Ch(x[i])),0);
	Make(scc[1],0);build();GetAns(scc[1],0);printf("%lld\n",ans%mod);
}
posted @ 2021-07-11 21:56  275307894a  阅读(34)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end