[乱搞]JZOJ 3738 理想城市(city)
分析
最简单竟然是NOI题
考虑从纵方向和横方向成树各做一次遍历,某路径的贡献显然是子树大小乘另外半边的子树大小
那么怎么构树呢?首先纵向相邻的连边,横向的瞎搞搞就行了
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <map> using namespace std; typedef long long ll; const ll P=1e9; const int N=1e5+10; struct Point { int x,y; friend bool operator < (Point a,Point b) {return a.x<b.x||a.x==b.x&&a.y>b.y;} }p[N]; struct Graph { int v,nx; }g[2*N]; int cnt,list[N],sz[N],f[N]; ll ans; int n; map<pair<int,int>,int> h; void Add(int u,int v) { if (v==g[list[u]].v) return; g[++cnt]=(Graph){v,list[u]};list[u]=cnt; g[++cnt]=(Graph){u,list[v]};list[v]=cnt; } void Connect() { sort(p+1,p+n+1); memset(f,0,sizeof f);h.clear();memset(list,0,sizeof list);cnt=0; for (int i=1;i<=n;i++) h[make_pair(p[i].x,p[i].y)]=i; for (int i=n;i;i--) { if (!f[i]) { f[i]=i;sz[i]=1; for (int j=i-1;j;j--) if (p[j].y==p[j+1].y+1) f[j]=i,sz[i]++; else break; } if (h[make_pair(p[i].x+1,p[i].y)]) Add(f[i],f[h[make_pair(p[i].x+1,p[i].y)]]); } } void DFS(int u,int f) { for (int i=list[u];i;i=g[i].nx) if (g[i].v!=f) DFS(g[i].v,u),sz[u]+=sz[g[i].v],(ans+=1ll*sz[g[i].v]*(n-sz[g[i].v])%P)%=P; } int main() { freopen("city.in","r",stdin); freopen("city.out","w",stdout); scanf("%d",&n); for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); Connect();DFS(f[1],0); for (int i=1;i<=n;i++) swap(p[i].x,p[i].y); Connect();DFS(f[1],0); printf("%lld",ans); }
在日渐沉没的世界里,我发现了你。