Time Limit: 1000 ms        Memory Limit: 128 MB

[吐槽]

  点分治点分治点分治

  嗯。。场上思考树状数组的时候好像傻掉了。。反正就是挂了就是了。。

[题解]

  首先如果没有环的话就是一道十分简单的点分治啦

  但是这题有环啊

  

  考虑强行变树

  从题目各种谜一般的描述中得出来的结论是:$m<=n$

  其实也就是说最多只有一个环

  那么就有一个很直接的想法,先把唯一的一个环找出来,断掉其中的一条边

  这样就使它变成一棵树了,直接跑一遍点分就好

  考虑断掉的那条边

  这样统计有一个很明显的问题:经过断开那条边的情况全部都没有算进去

  所以现在就考虑怎么算过这条边的ans

  

  首先我们可以将这个环摊开变成这样:

  

  

  然后发现这个东西其实就是一条“链”上面有若干棵树

  断开的那条边显然就是连接这条“链”一头一尾的边(为了方便描述,将这条断开的边记作$(x,y)$)

  我们定义

  $rt_i$表示$i$所属的子树的根节点

  $dis_i$ 表示$i$到$rt_i$的的路径上的点数

  $left_i$表示$rt_i$到这条“链”头(也就是图中编号为1的点)的节点数

  $right_i$表述$rt_i$到这条“链”尾(图中编号为5的点)的节点数

  那么要算一条过$(x,y)$的路径$(i,j)$的点数的话,显然就是子树里面的距离+链上要走的距离

  也就是 $dis_i+dis_j+left_i+right_j$ ($rt_i$在$rt_j$左边)

  

  那么就可以用一个树状数组来搞定了

  考虑怎么统计

  (其实实现起来并不用上面的那些奇妙数组)

  我们可以先将链上的点(也就是各个子树的根节点)编个号

  那么对于一个这条链上面的第$i$和第$j$ $(i<j)$ 个点,那么链上要走的距离就为 $i+(len-j+1)$

  其中$len$表示的是链的长度

  然后将式子上一步中求路径上点数的式子稍微整理一下,得到

  $(dis_i+i)+(dis_j+len-j+1)  (i<j) $

  

  所以我们可以从左往右一个一个点处理

  先将当前点$i$子树内的$dis$处理出来

  然后对于每一个$dis_j (j \in subtree(i))$ ,在树状数组里面查询大于等于$k-dis_j-(len-j+1)$的数量(原因在后面解释)

  查询完了之后将$dis_j+j$丢入树状数组中

  这么处理的原因显然

  整理过后的式子可以分为两部分,分别只与$i$和$j$有关

  然后因为我们是从左到右处理链上面的点的,所以可以保证查询到的点是在当前点的前面的

  然后这题就十分愉快地解决啦

[一些小细节]

  因为这题是求>=的方案数

  所以树状数组要十分愉快地反过来(也就是insert的时候是x-=x&-x,query的时候是x+=x&-x,见代码)

  以及因为insert的时候是dis+i,所以上限应该是2*n

  以及要用long long

  嗯大概就是这样ovo

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int MAXN=;
int h[MAXN],size[MAXN],mx[MAXN];
ll dis[MAXN];
bool vis[MAXN];
int n,m,k,tot,rt,rt_mx;
ll ans,num;
struct xxx
{
int y,next;
bool flag;
}a[MAXN*];
struct data
{
ll c[MAXN*];
int insert(int x,ll delta) {_insert(x,delta);}
int _insert(int x,ll delta)
{
for (;x;x-=x&-x) c[x]+=delta;
}
ll query(int x) {return _query(x);}
ll _query(int x)
{
ll ret=;
if (x<) x=;
for (;x<=*n;x+=x&-x) ret+=c[x];
return ret;
}
}c;
int pre[MAXN],cir[MAXN];
int add(int x,int y);
int dfs(int x);
int dfs_size(int x,int fa);
int dfs_root(int r,int x,int fa);
int get_dis(int x,int fa,int d);
int get_cir(int fa,int x);
ll cal(int x,int d);
bool cmp(int x,int y){return x>y;}
int solve_cir(); int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout); int x,y,z;
scanf("%d%d%d",&n,&m,&k);
tot=;
memset(h,-,sizeof(h));
for (int i=;i<=m;++i)
{
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
if (m+==n) {dfs(); printf("%lld\n",ans); return ;}
cir[]=;
get_cir(,);
solve_cir();
} int add(int x,int y)
{
a[++tot].y=y; a[tot].next=h[x]; h[x]=tot; a[tot].flag=true;
} int dfs(int x)
{
rt=,rt_mx=n;
dfs_size(x,);
dfs_root(x,x,);
ans=ans+cal(rt,);
vis[rt]=true;
for (int i=h[rt];i!=-;i=a[i].next)
if (!vis[a[i].y]&&a[i].flag)
{
ans=ans-cal(a[i].y,);
dfs(a[i].y);
}
} int dfs_size(int x,int fa)
{
size[x]=;
mx[x]=;
for (int i=h[x];i!=-;i=a[i].next)
if (a[i].y!=fa&&!vis[a[i].y]&&a[i].flag)
{
dfs_size(a[i].y,x);
size[x]+=size[a[i].y];
mx[x]=max(mx[x],size[a[i].y]);
}
} int dfs_root(int r,int x,int fa)
{
mx[x]=max(mx[x],size[r]-size[x]);
if (rt_mx>mx[x]) rt_mx=mx[x],rt=x;
for (int i=h[x];i!=-;i=a[i].next)
if (a[i].y!=fa&&!vis[a[i].y]&&a[i].flag)
dfs_root(r,a[i].y,x);
} int get_dis(int x,int fa,int d)
{
dis[++num]=d;
for (int i=h[x];i!=-;i=a[i].next)
if (a[i].y!=fa&&!vis[a[i].y]&&a[i].flag)
get_dis(a[i].y,x,d+);
} ll cal(int x,int d)
{
num=;
get_dis(x,,d);
int left=,right=num;
ll re=;
sort(dis+,dis++num,cmp);
while (left<right)
{
while (dis[left]+dis[right]+<k&&left<right) --right;
re+=right-left;
++left;
}
return re;
} int get_cir(int fa,int x)
{
int u;
vis[x]=true; pre[x]=fa;
for (int i=h[x];i!=-;i=a[i].next)
{
u=a[i].y;
if (u==fa) continue;
if (vis[u])
{
a[i].flag=false; a[i^].flag=false;
for (int j=x;j!=u;j=pre[j]) cir[++cir[]]=j;
cir[++cir[]]=u;
return ;
}
get_cir(x,u);
if (cir[]) return ;
}
} int solve_cir()
{
for (int i=;i<=n;++i) vis[i]=false;
dfs();
for (int i=;i<=n;++i) vis[i]=false;
for (int i=;i<=cir[];++i) vis[cir[i]]=true;
for (int i=;i<=cir[];++i)
{
num=;
get_dis(cir[i],,);
for (int j=;j<=num;++j)
ans+=c.query(k-dis[j]-(cir[]-i+));
for (int j=;j<=num;++j)
c.insert(dis[j]+i,);
}
printf("%lld\n",ans);
}

挫挫的代码

【noip模拟】tree的更多相关文章

  1. 8.22 NOIP 模拟题

      8.22 NOIP 模拟题 编译命令 g++ -o * *.cpp gcc -o * *.c fpc *.pas 编译器版本 g++/gcc fpc 评测环境 位 Linux, .3GHZ CPU ...

  2. NOIP 模拟赛

    NOIP 模拟赛 思路:求 n , m 的 gcd,然后用 n , m 分别除以 gcd:若 n 或 m 为偶数,则输出 1/2. 特别的,当 n = m = 1 时,应输出 1/1 #include ...

  3. 8.1 NOIP模拟11

    8.1 NOIP模拟 11 今天上午返校之后,颓了一会,然后下午就开始考试,中午睡着了,然后刚开始考试的时候就困的一匹,我一看T1,woc,这不是之前线段树专题的题啊,和那道题差不多,所以我..... ...

  4. 2019.7.29 NOIP模拟测试10 反思总结【T2补全】

    这次意外考得不错…但是并没有太多厉害的地方,因为我只是打满了暴力[还没去推T3] 第一题折腾了一个小时,看了看时间先去写第二题了.第二题尝试了半天还是只写了三十分的暴力,然后看到第三题是期望,本能排斥 ...

  5. NOIP模拟 17.8.15

    NOIP模拟17.8.15 A 债务文件名 输入文件 输出文件 时间限制 空间限制debt.pas/c/cpp debt.in debt.out 1s 128MB[题目描述]小 G 有一群好朋友,他们 ...

  6. noip模拟23[联·赛·题]

    \(noip模拟23\;solutions\) 怎么说呢??这个考试考得是非常的惨烈,一共拿了70分,为啥呢 因为我第一题和第三题爆零了,然后第二题拿到了70分,还是贪心的分数 第一题和第二题我调了好 ...

  7. noip模拟27[妹子图·腿·腰](fengwu半仙的妹子们)

    \(noip模拟27\;solutions\) 这次吧,我本来以为我能切掉两个题,结果呢??只切掉了一个 不过,隔壁Varuxn也以为能切两个,可惜了,他一个都没切...... 确实他分比我高一点,但 ...

  8. noip模拟6(T2更新

    由于蒟弱目前还没调出T1和T2,所以先写T3和T4.(T1T2更完辣! update in 6.12 07:19 T3 大佬 题目描述: 他发现katarina大佬真是太强了,于是就学习了一下kata ...

  9. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  10. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

随机推荐

  1. paping使用来测试联通&网站由于tcp协议导致的无法通信问题超时问题

    1. 使用paping来测试连通性 Linux 平台: : wget http://www.updateweb.cn/softwares/paping_1.5.5_x86-64_linux.tar.g ...

  2. [ZJOI2008]骑士

    [ZJOI2008]骑士 标签: DP 题目链接 题解 把边看成无向的. 其实就是求这个东西的最大独立集. 但是这不是树,怎么求呢? 其实还是一样的求法. 对于每一个连通块.最多有这个联通块的大小数目 ...

  3. easyui+ajax获取同表关联的数据

    easyui是我们常用的前端框架之一,easyui的使用使得前端页面更加美观.为了能够使用combobox,ajax必须同步. 该小程序是使用ssm框架,对数据库的数据进行查询,所以url对应着map ...

  4. [NOIP2001提高组]数的划分

    题目描述 将整数n分成k份,且每份不能为空,任意两个方案不相同(不考虑顺序). 例如:n=7,k=3,下面三种分法被认为是相同的. 1,1,5; 1,5,1; 5,1,1; 问有多少种不同的分法. 输 ...

  5. 通过实例介绍持续集成的应用--基于Jenkins

    1.测试工程师为什么要掌握持续集成 一个程序员如果想发布一个产品,他需要编码.编译.测试,发布的过程.对于一个企业来说,如果也想发布一个产品的话,同样的也是需要上述的过程,区别在于企业要发布的产品的需 ...

  6. node.js简单搭建服务,访问本地站点文件

    1.安装nodejs服务(从官网下载安装),node相当于apache服务器 2.在自己定义的目录下新建服务器文件如 server.js 例如,我在D:\nodeJs下创建了server.js文件 v ...

  7. java网络编程(2)——UDP与TCP

    首先,先介绍这两种协议: UDP:UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互 ...

  8. WinSock WSAEventSelect 模型总结

    前言 本文配套代码:https://github.com/TTGuoying/WSAEventSelect-model 由于篇幅原因,本文假设你已经熟悉了利用Socket进行TCP/IP编程的基本原理 ...

  9. Photoshop 样式的角度/高度选择器控件

    Conmajia © 2012 Updated on Mar. 5, 2018 简介 Adobe Photoshop有两个非常专业的控件:角度选择器和角度与高度选择器,如图1所示. 图1 两种控件外观 ...

  10. (2018干货系列三)最新PHP学习路线整合

    怎么学PHP PHP是一种通用开源脚本语言.语法吸收了C语言.Java和Perl的特点,利于学习,使用广泛,主要适用于Web开发领域. 菜鸟到大神,一步到位,正式开启干货模式: PHP初级开发工程师 ...