Hello,I'm LRX2015U41!
阿新 • • 發佈:2018-12-19
【題目描述】 眾所周知,小K是一隻連NOIP2018初賽都沒有過的蒟蒻,所以小K很擅長dfs序+分塊樹,但是本題與dfs序+分塊樹無關。 小K現在心態爆炸了,因為小K被一道簡單的資料結構題給卡住了,希望請你來解決它,但是小K又不想太麻煩你,於是將題面進行了簡化(其實是出題人懶得寫題面了233333): Bob有?個點的樹,每條邊的長度有一個邊權,現在定義???(?,?)代表第?個點到第?個點的距離模2之後的結果。問有多少(?,?,?)滿足,???(?,?) = ???(?,?) = ???(?,?)。
【輸入描述】 第一行一個整數?代表點的數量。 接下來? − 1行每行三個數?,?,?代表有一條在?,?之間長度為?的邊。
【輸出描述】 一行一個整數代表有多少對(?,?,?)滿足條件。
【輸入樣例】 3 1 2 3 1 3 4
【輸出樣例】 9
【資料範圍】 對於100%的資料,1 ≤ ? ≤ 10000,0 ≤ ? ≤ 233。
思路:原本想到了暴力寫部分分:倍增求最近公共祖先+樹上差分 ,事實上這種方法不僅不是正解而且效率很低,只能處理不到1000的資料量。
首先分析題目,模2之後的結果只能是0或1,三者相等的情況不可能等於1,可以畫出圖找找規律,只能等於0,然後通過Dfs找出每個點與根節點的關係,有兩種可能,到根節點路徑長為偶數,記為0,長為奇數,記為1,將個數分別記錄在cnt[0]和cnt[1]中,最後利用乘法原理解決問題。注意,此題不開long long會爆。
#include<iostream>
#include<cstdio>
#include<cstring>
#define mem(a,b) memset(a,b,sizeof a)
#define LL long long
using namespace std;
const int MAX_N=1e4+7;
int n;
int eid;
struct node{
int v,w,next;
}e[2*MAX_N];
int dist[MAX_N];
int p[MAX_N];
LL cnt[3];
void init()
{
mem(dist, 0);
mem(e,0);
mem(p,-1);
eid=0;
}
void insert(int u,int v,int w)
{
e[eid].v=v;
e[eid].w=w;
e[eid].next=p[u];
p[u]=eid++;
}
void insert2(int u,int v,int w)
{
insert(u,v,w);
insert(v,u,w);
}
void dfs(int u,int fa,int w)
{
dist[u]=(dist[fa]+w)%2;
cnt[dist[u]]++;
for(int i=p[u];~i;i=e[i].next)
{
if(e[i].v!=fa)
{
int v=e[i].v;
int w=e[i].w;
dfs(v,u,w);
}
}
}
LL Pow_3(LL x)
{
return x*x*x;
}
int main()
{
scanf("%d",&n);
init();
for(int i=1;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
insert2(u,v,w%2);
}
dfs(1,0,0);
printf("%lld",(LL)(Pow_3(cnt[0])+Pow_3(cnt[1])));
return 0;
}