?? pku 3321 樹狀數(shù)組.txt
字號:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
#define PB push_back
//PKU 3321 樹狀數(shù)組
#define NMAX 100005
#define MMAX 100005
#define INFI 99999999
typedef struct ooparc
{
int first;
int second;
}ooparc;
typedef struct oopnode
{
int begin;
int end;
int fa;
}oopnode;
typedef struct oopxulie
{
int data;
int has;
}oopxulie;
oopxulie xulie[NMAX*2+5];//DFS序列,data表示點的標號,has表示改點是否有蘋果
ooparc arc[MMAX*2];//重復邊集=輸入的arc序列+將first,second倒置后的序列
oopnode node[NMAX];//在重復邊集中,(arc.fisrt已排序),arc.first對應的開始點和結(jié)束點
oopnode node2[NMAX];//記錄DFS序列某點的第一次出現(xiàn)和第二次出現(xiàn)的位置
int xxx;
int szsz[NMAX*2+5];
int getlow(int k)
{
return k & (k ^ (k-1));
}
void add(int p)
{
while(p<NMAX*2)
{
szsz[p]++;
p+=getlow(p);
}
}
void del(int p)
{
while(p<NMAX*2)
{
szsz[p]--;
p+=getlow(p);
}
}
int getsum(int p)
{
int sum=0;
while(p>=1)
{
sum+=szsz[p];
p-=getlow(p);
}
return sum;
}
void print_xulie(int num)
{
int i;
for(i=1;i<=num;i++) printf("%d ",xulie[i].data);
printf("\n");
for(i=1;i<=num;i++) printf("%d ",xulie[i].has);
}
bool cmparc(ooparc a,ooparc b)
{
return a.first<b.first;
}
void build(int now)
{
int i,p;
xxx++;
xulie[xxx].has=1;
xulie[xxx].data=now;
node2[now].begin=xxx;
for(i=node[now].begin;i<=node[now].end;i++)
{
p=arc[i].second;
if(node[now].fa!=p)
{
node[p].fa=now;
build(p);
}
}
xxx++;
xulie[xxx].has=0;
xulie[xxx].data=now;
node2[now].end=xxx;
}
void change(int p)
{
if(xulie[node2[p].begin].has==0)
{
add(node2[p].begin);
xulie[node2[p].begin].has=1;
}
else
{
del(node2[p].begin);
xulie[node2[p].begin].has=0;
}
}
int cal(int p)
{
return getsum(node2[p].end)-getsum(node2[p].begin-1);
}
void init(int mnum)
{
// 假設(shè)樹的結(jié)構(gòu)是:
// 1
// 2 5
// 3 4 6
// 7
// 則編列得到的DFS序列為:
// 1 2 3 3 2 5 4 4 6 7 7 6 5 1
// 則某點的子樹為該序列里兩次出現(xiàn)的這一點之間的標號,我們稱其為該點的DFS區(qū)間
// 如標號5的子樹,對應的DFS區(qū)間為5 4 4 6 7 7 6 5
// 建樹時第一次出現(xiàn)的標號對應的has值為1,否則為0,則該DFS序列對應的has為:
// 1 1 1 0 0 1 1 0 1 1 0 0 0 0
// 要查找某點子樹的has值之和,只要求這一點的DFS區(qū)間上的has之和即可
// 求區(qū)間上的數(shù)之和,樹狀數(shù)組最擅長。
int i;
for(i=1;i<=mnum;i++)
{
arc[mnum+i].first=arc[i].second;
arc[mnum+i].second=arc[i].first;
}
sort(arc+1,arc+2*mnum+1,cmparc);
node[arc[1].first].begin=1;
for(i=2;i<=2*mnum;i++)
{
if(arc[i-1].first!=arc[i].first)
{
node[arc[i].first].begin=i;
node[arc[i-1].first].end=i-1;
}
}
node[arc[i-1].first].end=2*mnum;
for(i=1;i<NMAX;i++)
{
node[i].fa=-10;
}
node[1].fa=-1;
xxx=0;
build(1);
for(i=1;i<=2*mnum+2;i++)
{
if(xulie[i].has==1) add(i);
}
// print_xulie(2*mnum+2);
}
int main()
{
int num,i,qnum,x,y;
char str[3];
scanf("%d",&num);
for(i=1;i<=num-1;i++)
{
scanf("%d %d",&arc[i].first,&arc[i].second);
}
init(num-1);
scanf("%d",&qnum);
for(i=1;i<=qnum;i++)
{
scanf("%s %d",&str,&x);
if(str[0]=='Q') printf("%d\n",cal(x));
else change(x);
}
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -