2015-04-29 21:00:25
题目:莫队经典必A题。
思路:离线处理一下所有询问,对于一个询问,那么设其中有k种颜色的袜子,每种的数量是 a1,a2 ... ak ,那么答案显然是 (a1*(a1-1)/2 + a2*(a2-1)/2 + ... + ak*(ak-1)/2) / [(R-L+1)*(R-L)/2]
所以相邻询问[L,R] -> [L,R+1]之间可以O(1)转移。所以可用离线莫队搞之,学了两种实现方式,(1)曼哈顿距离最小生成树 (2)分块。
分析:无论从时间复杂度和空间复杂度上,分块都更优(当然是针对于部分问题)
方法一:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int MAXN = 50010; int N,M,block,co[MAXN],num[MAXN]; ll cur_val; struct Node{ int x,y,id,bid; ll A,B; }p[MAXN]; bool cmp(Node a,Node b){ return a.bid == b.bid ? a.y < b.y : a.x < b.x; } bool cmp2(Node a,Node b){ return a.id <b.id; } ll Gcd(ll a,ll b){ return b == 0 ? a : Gcd(b,a % b); } ll Sqr(ll x){ return x * x; } void Update(int l,int r,int d){ for(int i = l; i <= r; ++i){ cur_val -= Sqr((ll)num[co[i]]); num[co[i]] += d; cur_val += Sqr((ll)num[co[i]]); } } void Block(){ sort(p + 1,p + M + 1,cmp); int l = 1,r = 0; for(int i = 1; i <= M; ++i){ if(p[i].x < l) Update(p[i].x,l - 1,1); if(l < p[i].x) Update(l,p[i].x - 1,-1); if(r < p[i].y) Update(r + 1,p[i].y,1); if(p[i].y < r) Update(p[i].y + 1,r,-1); p[i].A = cur_val - (p[i].y - p[i].x + 1); p[i].B = (ll)(p[i].y - p[i].x + 1) * (p[i].y - p[i].x); ll g = Gcd(p[i].A,p[i].B); p[i].A /= g,p[i].B /= g; l = p[i].x; r = p[i].y; } sort(p + 1,p + M + 1,cmp2); for(int i = 1; i <= M; ++i) printf("%lld/%lld\n",p[i].A,p[i].B); } int main(){ scanf("%d%d",&N,&M); block = (int)sqrt(1.0 * N); for(int i = 1; i <=N; ++i) scanf("%d",co + i); for(int i = 1; i <= M; ++i){ scanf("%d%d",&p[i].x,&p[i].y); p[i].id = i; p[i].bid = p[i].x / block; } Block(); return 0; }
方法二:最小manhattan mst:
#include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i,n) for(int i=0;i<(n);++i) #define FOR(i,a,b) for(int i=(a);i<=(b);++i) #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 50010; int N,M,ecnt; int A[MAXN],B[MAXN],co[MAXN],fa[MAXN]; int first[MAXN],num[MAXN]; ll cur_val,rlt[MAXN][2]; vector<int> G[MAXN]; struct edge{ int u,v,c,next; bool operator < (const edge a)const { return c < a.c; } }e[MAXN << 2],E[MAXN << 1]; void add_edge(int u,int v,int c){ e[++ecnt].u = u; e[ecnt].v = v; e[ecnt].c = c; } struct Node{ int x,y,id; bool operator < (const Node a)const { return x == a.x ? y < a.y : x < a.x; } }p[MAXN],pb[MAXN]; struct BIT{ int tmax,c[MAXN],ps[MAXN]; void init(int tmp){ tmax = tmp; FOR(i,1,tmax) c[i] = INF; MEM(ps,-1); } int lowbit(int x){ return x & (-x); } void update(int x,int d,int pos){ while(x){ if(d < c[x]){ c[x] = d; ps[x] = pos; } x -= lowbit(x); } } int get(int x){ int res = INF,pos = -1; while(x <= tmax){ if(c[x] < res){ res = c[x]; pos = ps[x]; } x += lowbit(x); } return pos; } }bit; int Dis(int a,int b){ return abs(p[a].x - p[b].x) + abs(p[a].y - p[b].y); } int Find(int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]); } ll Gcd(ll a,ll b){ return b == 0 ? a : Gcd(b,a % b); } void Manhattan_mst(){ for(int dir = 1; dir <= 4; ++dir){ if(dir == 2 || dir == 4) FOR(i,1,M) swap(p[i].x,p[i].y); else if(dir == 3) FOR(i,1,M) p[i].y = -p[i].y; sort(p + 1,p + M + 1); FOR(i,1,M) A[i] = B[i] = p[i].y - p[i].x; sort(B + 1,B + M + 1); int sz = unique(B + 1,B + M + 1) - B; bit.init(sz); for(int i = M; i >= 1; --i){ int pos = lower_bound(B + 1,B + sz + 1,A[i]) - B; int ans = bit.get(pos); if(ans != -1) add_edge(p[i].id,p[ans].id,Dis(i,ans)); bit.update(pos,p[i].x + p[i].y,i); } } //Kruskal sort(e + 1,e + ecnt + 1); FOR(i,1,ecnt){ int x = Find(e[i].u); int y = Find(e[i].v); if(x != y){ fa[y] = x; G[e[i].u].PB(e[i].v); G[e[i].v].PB(e[i].u); } } } ll Cal(int v){ return (ll)v * (v - 1); } void Add(int l,int r){ FOR(i,l,r){ cur_val -= Cal(num[co[i]]); cur_val += Cal(++num[co[i]]); } } void Del(int l,int r){ FOR(i,l,r){ cur_val -= Cal(num[co[i]]); cur_val += Cal(--num[co[i]]); } } void Dfs(int l1,int r1,int l2,int r2,int id,int pre){ if(l2 < l1) Add(l2,l1 - 1); if(l2 > l1) Del(l1,l2 - 1); if(r2 > r1) Add(r1 + 1,r2); if(r2 < r1) Del(r2 + 1,r1); rlt[id][0] = cur_val; rlt[id][1] = (ll)(r2 - l2 + 1) * (r2 - l2); for(int i = 0; i < G[id].size(); ++i){ int v = G[id][i]; if(v == pre) continue; Dfs(l2,r2,pb[v].x,pb[v].y,v,id); } if(l2 < l1) Del(l2,l1 - 1); if(l2 > l1) Add(l1,l2 - 1); if(r2 > r1) Del(r1 + 1,r2); if(r2 < r1) Add(r2 + 1,r1); } void Init(){ MEM(first,-1); ecnt = 0; FOR(i,1,M) fa[i] = i; MEM(num,0); cur_val = 0; } int main(){ while(scanf("%d%d",&N,&M) != EOF){ FOR(i,1,N) scanf("%d",&co[i]); FOR(i,1,M){ scanf("%d%d",&p[i].x,&p[i].y); p[i].id = i; pb[i] = p[i]; } Init(); Manhattan_mst(); Dfs(1,0,pb[1].x,pb[1].y,1,-1); FOR(i,1,M){ ll g = Gcd(rlt[i][0],rlt[i][1]); printf("%lld/%lld\n",rlt[i][0] / g,rlt[i][1] / g); } } return 0; }