[树形DP] IOI 2012 Ideal city

34 篇文章 0 订阅


#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;

inline char nc(){
    static char buf[100000],*p1=buf,*p2=buf;
    if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }
    return *p1++;
}
inline void read(int &x){
    char c=nc(),b=1;
    for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
    for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int P=1e9;
const int N=100005;

const int dx[]={0,0,1,-1};
const int dy[]={1,-1,0,0};

int n;
struct abcd{
    int x,y;
    abcd(int x=0,int y=0):x(x),y(y) { }
    void read(){ ::read(x),::read(y); }
}a[N];
bool cmpx(abcd A,abcd B){ return A.x==B.x?A.y<B.y:A.x<B.x; }
bool cmpy(abcd A,abcd B){ return A.y==B.y?A.x<B.x:A.y<B.y; }

struct edge{
	int u,v,next;
}G[N<<1];
int head[N],inum;

inline void add(int u,int v,int p){
	G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;
}

struct node{
	int x,y1,y2; int l,r;
	node(int x=0,int y1=0,int y2=0,int l=0,int r=0):x(x),y1(y1),y2(y2),l(l),r(r) { }
}range[N];
int m;

ll ans=0;
ll sum[N],cnt[N];
int vst[N];

#define V G[p].v
inline void dfs(int u,int fa){
	ll tsum,tcnt;
	int l=range[u].l,r=range[u].r,y1=range[u].y1,y2=range[u].y2;
	for (int p=head[u];p;p=G[p].next)
		if (V!=fa)
			dfs(V,u);
	tsum=tcnt=0;
	for(int i=l;i<=r;i++){
		(tsum+=tcnt)%=P;
		(ans+=tsum*cnt[i]+sum[i]*tcnt)%=P;
		(tsum+=sum[i])%=P; tcnt+=cnt[i];
	}
	if (fa)
	{
		if (y1<range[fa].y1)
			for(int j=l;j<l+range[fa].y1-y1;j++)
				(sum[j+1]+=sum[j]+cnt[j])%=P,cnt[j+1]+=cnt[j];
		if (y2>range[fa].y2)
			for(int j=r;j>r-y2+range[fa].y2;j--)
				(sum[j-1]+=sum[j]+cnt[j])%=P,cnt[j-1]+=cnt[j];
		tsum=tcnt=0;
		for (int j=max(y1,range[fa].y1);j<=min(y2,range[fa].y2);j++)
		{
			int cur=l+j-y1;
			(ans+=(sum[cur]+cnt[cur])*cnt[range[fa].l+j-range[fa].y1]+sum[range[fa].l+j-range[fa].y1]*cnt[cur])%=P;
			(sum[range[fa].l+j-range[fa].y1]+=sum[cur]+cnt[cur])%=P;
			cnt[range[fa].l+j-range[fa].y1]+=cnt[cur];
			(tsum+=tcnt)%=P;
			(ans-=tsum*cnt[cur]+sum[cur]*tcnt)%=P; (ans+=P)%=P;
			(tsum+=sum[cur]+cnt[cur]*2)%=P; tcnt+=cnt[cur];
		}	
	}
}

int main()
{
    freopen("city.in","r",stdin);
    freopen("city.out","w",stdout);
    read(n);
    for (int i=1;i<=n;i++) a[i].read();
    sort(a+1,a+n+1,cmpx);
    int k=1;
	for(int i=2;i<=n;++i)
		if(a[i].x!=a[i-1].x||a[i].y!=a[i-1].y+1)
			range[++m]=node(a[k].x,a[k].y,a[i-1].y,k,i-1),k=i;
	range[++m]=node(a[k].x,a[k].y,a[n].y,k,n);
	int st=1,ed=0;
	for(int i=1;i<=m;++i)
	{
		if(i>1 && range[i].x!=range[i-1].x) st=ed+1,ed=i-1;
		while (st<=ed && range[st].y2<range[i].y1) st++;
		if (st<=ed && range[st].y1<=range[i].y2)
		{
			for (;st<=ed && range[st].y1<=range[i].y2;st++)
				add(i,st,++inum),add(st,i,++inum);
			st--;
		}
	}
	for (int i=1;i<=n;i++) cnt[i]=1,sum[i]=0;
	dfs(1,0);
	printf("%lld\n",ans);
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值