• BZOJ3648:寝室管理


    浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=3648

    基环树分治,结合了点分和边分的思想。

    先随便拆掉环上一条边,我们先称它为基边,把它当做树做一遍,跟Free Tour II差不多。

    剩下的问题就是如何统计经过基边的路径条数了。我们将基边连着的两个点分别成为(st)(ed)(st)的顺时针方向是(ed)(ed)的逆时针方向是(st)。直接跟边分一样去分别处理(st)(ed)能延伸出去的路径长度不行,因为这样会在环上产生交集然后统计不合法的路径。所以我们枚举基边以外的边去断开再统计答案,就可以保证统计出来的答案不重不漏了。

    然后因为只要做一遍,所以大力树状数组也没关系。

    时间复杂度:(O(nlogn))

    空间复杂度:(O(n))

    代码如下:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    typedef long long ll;
    #define low(i) ((i)&(-(i)))
    
    const int maxn=1e5+5;
    
    ll ans;
    bool vis[maxn],bo;
    int n,m,limit,tot=1,id,mx,rt,N;
    int now[maxn],pre[maxn*2],son[maxn*2];
    int siz[maxn],f[maxn],g[maxn],depest[maxn],V[maxn];
    
    int read() {
    	int x=0,f=1;char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
    	for(;ch>='0'&&ch<='9';ch=getchar())x=x*10+ch-'0';
    	return x*f;
    }
    
    void add(int a,int b) {
    	pre[++tot]=now[a];
    	now[a]=tot,son[tot]=b;
    }
    
    struct TreeArray {
    	int c[maxn];
    
    	void change(int pos,int v) {
    		if(pos==n-13)mx++;
    		for(int i=pos;i<=n;i+=low(i))
    			c[i]+=v;
    	}
    
    	int query(int pos) {
    		int res=0;
    		for(int i=pos;i;i-=low(i))
    			res+=c[i];
    		return res;
    	}
    }T;
    
    struct ring {
    	int node1,node2;
    	int dis[maxn],nxt[maxn],lst[maxn];
    
    	bool find_ring(int fa,int u) {
    		vis[u]=1;
    		for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    			if(v!=fa) {
    				if(vis[v])id=p>>1,node1=v,node2=u;
    				if(vis[v]||find_ring(u,v)) {
    					nxt[u]=v,lst[v]=u;
    					return 1;
    				}
    			}
    		return 0;
    	}
    
    	void dfs(int fa,int u,int num) {
    		if(num==1)dis[u]=dis[fa]+1;
    		T.change(n-dis[u]+1,num);
    		for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    			if(!vis[v]&&v!=fa)dfs(u,v,num);
    	}
    
    	void query(int fa,int u) {
    		dis[u]=dis[fa]+1,ans+=T.query(n-(max(1,limit-dis[u]))+1);
    		for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    			if(!vis[v]&&v!=fa)query(u,v);
    	}
    
    	void work() {
    		lst[node1]=node2;
    		memset(vis,0,sizeof(vis));
    		int st=son[id<<1],ed=son[id<<1|1];
    		if(nxt[st]==ed)swap(st,ed);
    		int pos=st;vis[ed]=1;
    		while(pos!=ed)vis[pos]=1,pos=nxt[pos];
    		dis[ed]=0,pos=st;mx=0;
    		while(pos!=ed)dfs(lst[pos],pos,1),pos=nxt[pos];dfs(lst[ed],ed,1);
    		pos=ed;dis[st]=0;
    		while(pos!=st)dfs(nxt[pos],pos,-1),query(nxt[pos],pos),pos=lst[pos];
    	}
    }R;
    
    void find_rt(int fa,int u) {
    	int res=0;siz[u]=1;
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&(p>>1)!=id&&v!=fa)
    			find_rt(u,v),siz[u]+=siz[v],res=max(res,siz[v]);
    	res=max(res,N-siz[u]);
    	if(res<mx)mx=res,rt=u;
    }
    
    void dfs(int fa,int u,int dep) {
    	mx=max(mx,dep),siz[u]=1;
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&(p>>1)!=id&&v!=fa)
    			dfs(u,v,dep+1),siz[u]+=siz[v];
    }
    
    bool cmp(int a,int b) {
    	return depest[a]<depest[b];
    }
    
    void query(int fa,int u,int dep) {
    	ans+=f[max(1,limit-dep)];
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&v!=fa&&(p>>1)!=id)query(u,v,dep+1);
    }
    
    void solve(int fa,int u,int dep) {
    	g[dep]++;
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&v!=fa&&(p>>1)!=id)solve(u,v,dep+1);
    }
    
    void work(int u,int size) {
    	N=size,mx=rt=n+1,find_rt(0,u),u=rt,vis[u]=1,tot=0;
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&(p>>1)!=id) {
    			V[++tot]=v,mx=0;
    			dfs(u,v,2),depest[v]=mx;
    		}
    	sort(V+1,V+tot+1,cmp);
    	for(int i=1;i<=tot;i++) {
    		query(u,V[i],1);
    		solve(u,V[i],2);
    		for(int j=depest[V[i]];j;j--)
    			g[j]+=g[j+1],f[j]+=g[j];
    		for(int j=1;j<=depest[V[i]];j++)g[j]=0;
    	}
    	ans+=f[limit];
    	for(int i=1;i<=depest[V[tot]];i++)f[i]=g[i]=0;
    	for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
    		if(!vis[v]&&(p>>1)!=id)work(v,siz[v]);
    }
    
    int main() {
    	n=read(),m=read(),limit=read();
    	for(int i=1;i<=m;i++) {
    		int a=read(),b=read();
    		add(a,b),add(b,a);
    	}
    	if(m==n)R.find_ring(0,1);
    	memset(vis,0,sizeof(vis));
        work(1,n);
    	if(m==n)R.work();
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    对于Volatile的认识
    TextView图文混排
    android自定义控件
    我最喜欢的SQL分页查询方法
    nopCommerce开发者指南(十):开发者怎样为nopCommerce 项目贡献代码?
    nopCommerce开发者指南(九):设置 API
    nopCommerce开发者指南(八):暴露和处理事件
    nopCommerce开发者指南(七):计划任务
    nopCommerce开发者指南(六):数据验证
    nopCommerce开发者指南(五):怎样注册新路由?
  • 原文地址:https://www.cnblogs.com/AKMer/p/10123878.html
Copyright © 2020-2023  润新知