http://acm.hdu.edu.cn/showproblem.php?pid=4358
map 版本 ?
比賽的時候也用map 寫了 不過沒有加優化 所以超時了
調試了一上午 ?下午自己出數據測了一下才知道那里出錯了 汗
大體思路:
用map<int , int > 保存子樹某個數出現的次數 然后從葉子節點向上更新合并 合并的時候需要 size小的向size大
的上面合并 這樣省時 這是由map 的構造決定的
用c++ 提交要 手動開棧 ?否則會棧溢出 ?用G++ 提交可以避免但花費時間要長一些
自測數據 對我來說很重要的一組數據 就是這里錯了一上午
1
6 1
1 2 3 4 5 6
1 2
1 3
3 4
3 5
1 6
6
1
2
3
4
5
6
詳情及其細節見代碼及其注釋:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<cmath>
#define LL long long
//#pragma comment(linker, "/STACK:102400000,102400000")//c++提交的話 需要手動開棧(看解析上的) g++不用 但時間花費長
using namespace std;
const int N=100005;
int head[N];//鄰接表 表頭
struct node
{
int j;
int next;
}side[N*2];
int son[N];//兒子節點個數
int f[N];//保存父節點
int id[N];//某個節點對應相關數據存在了哪個map里面 由于合并的關系 剛開始 i和id[i]對應相等 但一定的合并后就變了
int ans[N];//保存答案 離線保存要用
map<int ,int>str[N];
map<int ,int>:: iterator it,it1;
queue<int>qu;
int K;
void build(int x,int i)
{
side[i].next=head[x];
head[x]=i;
}
void dfs(int x,int pre)//用dfs求的本節點的父節點 和兒子節點數 和將葉子節點加入隊列
{
int t=head[x];
f[x]=pre;
while(t!=-1)
{
if(side[t].j!=pre)
{
dfs(side[t].j,x);
++son[x];
}
t=side[t].next;
}
if(son[x]==0)
{
qu.push(x);
}
}
void Add(int I,int i,int j)//將 map j 合并到i當中 將答案ans[I]進行更新
{
for(it=str[j].begin();it!=str[j].end();++it)//it 遍歷map j 的元素
{
it1=str[i].find(it->first);//到i 中查詢
if(it1==str[i].end())//未找到
{
str[i][it->first]=it->second;//加入
if(it->second==K)//如果正好等于K 則答案加一
++(ans[I]);
continue;
}
if(it1->second==K)//如果找到 本來在i中 這個數出現次數正好為K 在加上一個非0數則不等于K 了所以答案個數減1
--(ans[I]);
if((it1->second+=it->second)==K)//如果加上正好為K 答案個數加1 這不會和上一個沖突
++(ans[I]);
}
}
int main()
{
//freopen("data.txt","r",stdin);
int T;
scanf("%d",&T);
for(int cas=1;cas<=T;++cas)
{
memset(head,-1,sizeof(head));
memset(ans,0,sizeof(ans));
memset(son,0,sizeof(son));//各種初始化
while(!qu.empty())
qu.pop();
int n,q;
scanf("%d %d",&n,&K);
for(int i=1;i<=n;++i)
{
int a;
str[i].clear();//清空
id[i]=i;//本來每個節點 的map 就是自己對應的
scanf("%d",&a);
str[i][a]=1;//先都加入 本節點的數
if(K==1)//如果K正好為1 則答案也更新
++ans[i];
}
int x,y;
for(int i=1;i<n;++i)//輸入邊 建樹
{
scanf("%d %d",&x,&y);
side[i].j=y;
build(x,i);
side[i+n].j=x;
build(y,i+n);/
}
dfs(1,0);//搜一個
while(!qu.empty())
{
int l=qu.front();//取元素
if(l==1)
break;//如果到了1 則全求出 可以停止
qu.pop();
int fa=f[l];//fa為父親節點
--son[fa];//父親節點的可以更新的兒子節點減少1
if(son[fa]==0)//這是最后一個兒子節點 這是將fa加入隊列 千萬不能第一次更新就加入
{//否則會出現父節點在兒子節點前面的情況 就錯了(自己輸在這里了) 見上面數據
qu.push(fa);
}
int li=id[l];//找到對應的map
int fai=id[fa];
if(str[fai].size()>str[li].size())//比較大小
{
Add(fa,fai,li);
}else
{
ans[fa]=ans[l];//如果需要往l上合并 則先等于l的ans 在下面更新后ans[fa] 始終保存當前對應map里面的答案
id[fa]=li;//更改對應的map
Add(fa,li,fai);//更新
}
}
scanf("%d",&q);
printf("Case #%d:\n",cas);
while(q--)
{
scanf("%d",&x);
printf("%d\n",ans[x]);
}
if(cas<T)
printf("\n");
}
return 0;
}
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

