1. 程式人生 > >[2016陝西省賽D] Rui and her triangles

[2016陝西省賽D] Rui and her triangles

2016陝西省賽D
給定一棵大小為N的樹,每個節點有個權值a_i
詢問每個節點為根的子樹中,取三個點的權值構成三角形的方案數
其中 N,a_i < 1000

賽上懵逼了,實際上這題和貢獻有關
考慮列舉兩個點,權值為 xy(x>y)
那麼第三個點的範圍在 (xy,x+y)
接著我們找出這兩個點的lca,
那麼從lca為根的子樹會受到這兩個點的影響
之後再列舉lca為根的子樹內的剩下的另一個點,
計算這個點被多少這樣的區間所覆蓋
最後去重即可,統計去重的複雜度都是 (N2)

具體做法就是用靜態區間加的方式
先把這個影響標記到 lca上,之後把影響暴力向上合併

#pragma comment(linker, "/STACK:102400000,102400000")
#include <cstdio>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <map>
#include <set>
#include <queue>
#include <bitset>
#include <string> #include <complex> using namespace std; typedef pair<int,int> Pii; typedef long long LL; typedef unsigned long long ULL; typedef double DBL; typedef long double LDBL; #define MST(a,b) memset(a,b,sizeof(a)) #define CLR(a) MST(a,0) #define SQR(a) ((a)*(a)) #define PCUT puts("\n----------")
#define PRI(x) cout << #x << ":" << x << endl; const int maxn = 1e3+5; struct Graph { int ndn,edn,last[maxn]; int u[maxn], v[maxn], nxt[maxn]; void init(int _n){ndn=_n; edn=0; MST(last,-1);} void adde(int _u,int _v) { u[edn]=_u; v[edn]=_v; nxt[edn]=last[_u]; last[_u]=edn++; } }; struct LCA { Graph *G; int dfst, dfsn[maxn], ndfs[maxn], fir[maxn]; int stp, st[12][maxn<<1]; void init(Graph*,int); void dfs(int,int); int query(int,int); }; int N; Graph G; LCA lca; int val[maxn], psum[maxn]; int all[maxn][maxn]; int cnt[maxn][maxn]; LL ans[maxn]; void dfs(int); int main() { #ifdef LOCAL freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout); #endif int T; scanf("%d", &T); for(int ck=1; ck<=T; ck++) { printf("Case #%d:\n", ck); scanf("%d", &N); G.init(N); for(int i=2,x; i<=N; i++) { scanf("%d", &x); G.adde(x, i); } for(int i=1; i<=N; i++) scanf("%d", &val[i]); lca.init(&G,1); CLR(cnt); CLR(all); for(int i=1; i<=N; i++) for(int j=i+1; j<=N; j++) { int c = lca.query(i,j); int l=abs(val[i]-val[j])+1, r = min(val[i]+val[j], 1001); cnt[c][l]++; cnt[c][r]--; } dfs(1); for(int i=1; i<=N; i++) cout << ans[i]/3 << "\n"; } return 0; } void dfs(int u) { all[u][val[u]] = 1; ans[u] = 0; for(int e=G.last[u],v; ~e; e=G.nxt[e]) { v = G.v[e]; dfs(v); for(int i=1; i<=1000; i++) { all[u][i] += all[v][i]; cnt[u][i] += cnt[v][i]; } } for(int i=1; i<=1000; i++) psum[i] = psum[i-1] + all[u][i]; LL now = 0; int p = 0; for(int i=1; i<=1000; i++) if(all[u][i]) { for(; p+1<=i; p++) now += cnt[u][p+1]; ans[u] += now*all[u][i]; ans[u] -= 1LL*all[u][i]*(psum[min(2*i-1,1000)]-1); } } void LCA::init(Graph *g, int root) { G=g; stp = 0; dfst = 0; CLR(dfsn); CLR(ndfs); CLR(fir); dfs(root,-1); // for(int i=1; i<=stp; i++) printf("%d ", st[0][i]); // puts(""); for(int j=1; j<12; j++) { int len = 1<<(j-1), lim = stp-(1<<j)+1; for(int i=1; i<=lim; i++) st[j][i] = min(st[j-1][i], st[j-1][i+len]); } } void LCA::dfs(int u, int f) { dfsn[u] = ++dfst; ndfs[dfst] = u; st[0][++stp] = dfsn[u]; fir[u] = stp; for(int e=G->last[u],v; ~e; e=G->nxt[e]) if((v=G->v[e])!=f) { dfs(v, u); st[0][++stp] = dfsn[u]; } } int LCA::query(int u, int v) { int l=fir[u], r=fir[v]; if(l>r) swap(l,r); int flr=log2(r-l+1), len=1<<flr; return ndfs[min(st[flr][l], st[flr][r-len+1])]; }