1. 程式人生 > >Hello,I'm LRX2015U41!

Hello,I'm LRX2015U41!

【題目描述】 眾所周知,小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; }