考慮一對情侶(x,y)x<y的貢獻,設in[x],out[x]為數的dfs序。
強制從x走向y方向
-
當in[x]<in[y]且out[y]<=out[x] 矩形{1,in[x],in[y],out[y]},{out[x]+1,n,in[y],out[y]},{(in[x]+1,in[z]-1,in[y],out[y]},{out[z]+1,out[x],in[y],out[y]},z是x所在的y的兒子子樹的根
-
當in[y]<in[x]且out[x]<=out[y] 情況類似
-
其餘情況 矩形{in[x],out[x],in[y],out[y]}
這樣平面上所有落在矩形內的點P(x,y)x<=y是不合法的。
但是這樣並不好算。
於是乾脆算出有序點對數,及忽略走向,因為點(x,x)一定不被包含在矩形內,所以答案為(n^2-不合法的有序點對-n)/2。
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int head[N],to[N<<1],last[N<<1];
int fa[N][20],dep[N],in[N],out[N];
void add_edge(int x,int y) {
static int cnt=0;
to[++cnt]=y,last[cnt]=head[x],head[x]=cnt;
}
void dfs(int x,int pa) {
static int cnt=0;
in[x]=++cnt;
dep[x]=dep[fa[x][0]=pa]+1;
for(int i=1; (1<<i)<dep[x]; ++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=head[x]; i; i=last[i])
if(to[i]!=pa) dfs(to[i],x);
out[x]=cnt;
}
struct tree {
int cover,len;
} t[N<<2];
#define ls (x<<1)
#define rs (x<<1|1)
void update(int x,int l,int r) {
if(t[x].cover) t[x].len=r-l+1;
else if(l==r) t[x].len=0;
else t[x].len=t[ls].len+t[rs].len;
}
void modify(int x,int l,int r,int L,int R,int w) {
if(L<=l&&r<=R) {
t[x].cover+=w;
update(x,l,r);
return;
}
int mid=(l+r)>>1;
if(L<=mid) modify(ls,l,mid,L,R,w);
if(mid<R) modify(rs,mid+1,r,L,R,w);
update(x,l,r);
}
#undef ls
#undef rs
struct seg {
int type,h,l,r;
bool operator<(const seg&d) const {
return h!=d.h?h<d.h:type<d.type;
}
} s[N<<3];
int n,m,cnt;
void add_matrix(int a,int b,int c,int d) {
if(a>b||c>d) return;
s[++cnt]=(seg){1,c,a,b};
s[++cnt]=(seg){-1,d+1,a,b};
}
long long get_area() {
long long ret=0;
sort(s+1,s+cnt+1);
for(int i=1; i<cnt; ++i) {
modify(1,1,n,s[i].l,s[i].r,s[i].type);
ret+=1LL*(s[i+1].h-s[i].h)*t[1].len;
}
return ret;
}
void insert(int x,int y) {
if(in[x]<in[y]&&out[y]<=out[x]) {
add_matrix(1,in[x],in[y],out[y]);
add_matrix(out[x]+1,n,in[y],out[y]);
int dif=dep[y]-dep[x]-1,z=y;
for(int i=19; ~i; --i) if((dif>>i)&1) z=fa[z][i];
add_matrix(in[x]+1,in[z]-1,in[y],out[y]);
add_matrix(out[z]+1,out[x],in[y],out[y]);
return;
}
if(in[y]<in[x]&&out[x]<=out[y]) {
add_matrix(in[x],out[x],1,in[y]);
add_matrix(in[x],out[x],out[y]+1,n);
int dif=dep[x]-dep[y]-1,z=x;
for(int i=19; ~i; --i) if((dif>>i)&1) z=fa[z][i];
add_matrix(in[x],out[x],in[y]+1,in[z]-1);
add_matrix(in[x],out[x],out[z]+1,out[y]);
return;
}
add_matrix(in[x],out[x],in[y],out[y]);
}
int main() {
scanf("%d%d",&n,&m);
for(int x,y,i=n; --i; ) {
scanf("%d%d",&x,&y);
add_edge(x,y);
add_edge(y,x);
}
dfs(1,0);
for(int x,y,i=1; i<=m; ++i) {
scanf("%d%d",&x,&y);
insert(x,y);
insert(y,x);
}
printf("%lld
",(1LL*n*n-get_area()-n)/2);
return 0;
}
突然想到一道以前的題,直接扔下思路好了(可能有點鍋)
rb有一棵樹,樹的每個節點有個顏色。給一個長度為(n)的顏色序列,定義(s(i,j)) 為(i) 到(j) 的顏色數量。以及
[
sum_i=sum_{j=1}^ns(i,j)
]
現在他想讓你求出所有的(sum_i) 。((1le n,c[i]le 10^5))預處理出樹的DFS序((in[])和(out[]))對於樹上的一個點 (v) ,設其顏色是 (c) 。令 ((i,j)) 對應二維平面上的一個點。則 (v) 會對以下兩類 (s(i,j)) 產生貢獻:
- (i) 和 (j) 一個在(v) 的子樹外,一個在子樹內。
- (iin[1,in_v]) ,(jin[in_v,out_v])
- (iin[in_v,out_v]) ,(jin(out_v,n]) 。
- (iin[in_v,out_v]) ,(jin[1,in_v]) 。
- (iin(out_v,n]) ,(jin[in_v,out_v]) 。
- (i) 和 (j) 分別位於以 (v) 的不同兒子為根的兩個子樹中。列舉一個兒子(s)
- (iin[in_v,in_s)),(jin[in_s,out_s])。
- (iin[in_s,out_s]),(jin(out_s,out_v])。
- (iin[in_s,out_s]),(jin[in_v,in_s))。
- (iin(out_s,out_v]),(jin[in_s,out_s])。
把 ({iindots,jindots}) 看作覆蓋在二維平面上的一個矩形。把同是顏色(c) 的點的相關矩形單獨討論,若((i,j)) 被某個矩形覆蓋,則表示(i
ightarrow j) 路徑上存在顏色(c) 。我們考慮進行掃描線,對線所在位置的點進行差分記錄位置上被覆蓋的點有幾個(相應地有一個消除標記),在顏色討論完後求一個字首和,那麼答案就出來了。