hdu 5877 离散化+树状数组+dfs序
2016-09-13 17:09
323 查看
点击打开链接
参考点击打开链接
第一个要求u 是v 的祖先,那么可以dfs,遍历到v时,要使上方的都是满足第一条件的u,即遍历完某个节点u的子树时,这时u不可能是任何节点的祖先 删除u的影响,这样就能保证所有有影响的都是祖先。要求w[u]*w[v]<=k,那么到v的时候,所有小于等于k/w[v]的u都满足,可以想到树状数组。结点的值最大10亿,肯定要离散化,离散化的时候要把k/w[v]加进去一起离散。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
const int inf=1<<20;
const int M = 1e6+5;
vector<int> e[M];
int vis[M];
int in[M];//in[i]为0的为root
long long n,k;
long long a[M*2];
long long c[M<<1];
long long ans,data[2*M];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int val)
{
while(x<2*n)
{
c[x]+=val;
x+=lowbit(x);//往右上走
}
}
int sum(int x)
{
int s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
void dfs(int rt)
{
vis[rt]=1;
ans+=sum(a[rt+n]);//在它之前进入的都为它的祖先(兄弟节点在遍历完之后已经删除)
update(a[rt],1);
//au*av<=k 祖先节点要满足au<=k/a[v]
for(int i=0;i<e[rt].size();i++)
{
int son=e[rt][i];
if(!vis[son])
{
dfs(son);
}
}
update(a[rt],-1);//该节点的子树全都遍历完了 该节点不是任何节点的祖先时 删除该节点的值
}
void prepare(long long *x) //离散化模板
{
for(int i=1;i<=2*n;i++) data[i]=x[i];
sort(data+1,data+2*n+1);
int m=unique(data+1,data+2*n+1)-data-1;
for(int i=1;i<=2*n;i++) x[i]=lower_bound(data+1,data+m+1,x[i])-data;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>k;
ans=0;
memset(in,0,sizeof(in));
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
e[i].clear();
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(a[i]==0)
a[i+n]=M;
else
a[i+n]=k/a[i];
}
prepare(a);//数据a[i]<=10^9 n<=10^5 数据离散化使a[i]的范围中10^5内
//使得树状数组的空间不溢出
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
in[v]++;
}
int root;
for(int i=1;i<=n;i++)
{
if(!in[i])
{
root=i;
break;
}
}
dfs(root);
cout<<ans<<endl;
}
return 0;
}
参考点击打开链接
第一个要求u 是v 的祖先,那么可以dfs,遍历到v时,要使上方的都是满足第一条件的u,即遍历完某个节点u的子树时,这时u不可能是任何节点的祖先 删除u的影响,这样就能保证所有有影响的都是祖先。要求w[u]*w[v]<=k,那么到v的时候,所有小于等于k/w[v]的u都满足,可以想到树状数组。结点的值最大10亿,肯定要离散化,离散化的时候要把k/w[v]加进去一起离散。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdio>
using namespace std;
const int inf=1<<20;
const int M = 1e6+5;
vector<int> e[M];
int vis[M];
int in[M];//in[i]为0的为root
long long n,k;
long long a[M*2];
long long c[M<<1];
long long ans,data[2*M];
int lowbit(int x)
{
return x&(-x);
}
void update(int x,int val)
{
while(x<2*n)
{
c[x]+=val;
x+=lowbit(x);//往右上走
}
}
int sum(int x)
{
int s=0;
while(x>0)
{
s+=c[x];
x-=lowbit(x);
}
return s;
}
void dfs(int rt)
{
vis[rt]=1;
ans+=sum(a[rt+n]);//在它之前进入的都为它的祖先(兄弟节点在遍历完之后已经删除)
update(a[rt],1);
//au*av<=k 祖先节点要满足au<=k/a[v]
for(int i=0;i<e[rt].size();i++)
{
int son=e[rt][i];
if(!vis[son])
{
dfs(son);
}
}
update(a[rt],-1);//该节点的子树全都遍历完了 该节点不是任何节点的祖先时 删除该节点的值
}
void prepare(long long *x) //离散化模板
{
for(int i=1;i<=2*n;i++) data[i]=x[i];
sort(data+1,data+2*n+1);
int m=unique(data+1,data+2*n+1)-data-1;
for(int i=1;i<=2*n;i++) x[i]=lower_bound(data+1,data+m+1,x[i])-data;
}
int main()
{
int t;
cin>>t;
while(t--)
{
cin>>n>>k;
ans=0;
memset(in,0,sizeof(in));
memset(c,0,sizeof(c));
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
e[i].clear();
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
if(a[i]==0)
a[i+n]=M;
else
a[i+n]=k/a[i];
}
prepare(a);//数据a[i]<=10^9 n<=10^5 数据离散化使a[i]的范围中10^5内
//使得树状数组的空间不溢出
for(int i=1;i<=n-1;i++)
{
int u,v;
scanf("%d%d",&u,&v);
e[u].push_back(v);
in[v]++;
}
int root;
for(int i=1;i<=n;i++)
{
if(!in[i])
{
root=i;
break;
}
}
dfs(root);
cout<<ans<<endl;
}
return 0;
}
相关文章推荐
- mongodb remove
- C++_Primer_chapter17 2.命名空间
- linux ifcfg-eth0文件配置静态ip(centos-6.5)
- linux培训第四周作业
- HttpURLConnection用法详解
- Description Resource Path Location Type Java compiler level does not match the version of the instal
- IE 的浏览器模式和文本模式(一)
- SQL语句学习
- html5 video 视频标签详解
- MIT计算机科学集编程导论(一)
- mongodb update
- Tandem Features or Bottleneck Features
- 安装 kafka_2.11-0.10.0.1 遇到的问题
- 在Ubuntu15.10下安装Storm集群(一个机器上运行Nimbus和Supervisor 适合初学者)
- myeclipse +svn
- 配置文件参数的介绍
- H5移动端开发-JavaScript知识点
- yum安装rz,sz
- sdf
- C++中头文件(.h)和源文件(.cpp)都应该写些什么