题目链接:最强跳蚤

  这道题本来不想写博客的……但是鉴于自己犯了低级错误,还是写篇博客记载一下。

  一开始我的想法和题解里面的算法而比较类似,也是先分解质因数,然后用质因子是否出现偶数次来判断当前这个数是否是完全平方数……

  然而这样并不能AC,于是我去翻了题解……\(get\)了一个新做法,就是给每个出现过的质因子赋一个\([0,2^{64})\)的随机值,那么判断一个质因子是否出现偶数次就只需要判断异或和是否为零了。算一算可以发现冲突的概率非常小(但是我不会算)。

  然后……我就愉快的写了一发树分治……就当我练了一发板子好了(正好保存一份树分治板子)……

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010
#define maxp 10010
#define mod 999983 using namespace std;
typedef unsigned long long llg; int pri[maxp],lp,a[maxn],la,n,d[maxn];
int head[maxn],next[maxn<<1],to[maxn<<1],tt;
int w[maxn],siz[maxn],maxv[maxn],ld;
int h1[mod],n1[mod],ci[mod],_t,hd[mod],_d;
llg c1[maxn],val[maxn],c[maxn<<1],ans,INF,t1[mod];
bool vis[maxn]; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} llg ra(){llg x=(llg)rand()*(llg)rand()+(llg)rand();return x==INF?ra():x;}
void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
} void pre(){
for(int i=2;i<maxp;i++){
if(!vis[i]) pri[++lp]=i;
for(int j=1;j<=lp && pri[j]*i<maxp;j++){
vis[pri[j]*i]=1;
if(!(i%pri[j])) break;
}
}
for(int i=1;i<=lp;i++) val[i]=ra();
} void dfs1(int u,int fa){
siz[u]=1; maxv[u]=0; d[++ld]=u;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!vis[v] && v!=fa){
dfs1(v,u),siz[u]+=siz[v];
maxv[u]=max(maxv[u],siz[v]);
}
} void dfs2(int u,llg now){
vis[u]=1; c1[++ld]=now; if(!now) ans++;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(!vis[v]) dfs2(v,now^c[i]);
vis[u]=0;
} int find(llg x){
int u=x%mod;
for(int i=h1[u];i;i=n1[i])
if(t1[i]==x) return i;
return 0;
} int insert(llg x){
int j=find(x);
if(j){ci[j]++;return j;}
int u=x%mod; hd[++_d]=u; ci[++_t]=1;
t1[_t]=x; n1[_t]=h1[u];h1[u]=_t;
return _t;
} void solve(int u){
ld=0; dfs1(u,0); int _k=n+1,k;
for(int i=1,l,x;l=d[i],i<=ld;i++){
x=max(maxv[l],siz[u]-siz[l]);
if(x<_k) _k=x,k=l;
}
vis[k]=1; ld=_d=0;
for(int i=head[k];i;i=next[i])
if(!vis[to[i]]){
ld=0; dfs2(to[i],c[i]); sort(c1+1,c1+ld+1);
for(int j=1,k;k=j,j<=ld;j=k+1){
while(k<ld && c1[k+1]==c1[j]) k++;
ans+=(llg)(ci[find(c1[j])])*(llg)(k-j+1);
}
for(int j=1,k,x;k=j,j<=ld;j=k+1){
while(k<ld && c1[k+1]==c1[j]) k++;
x=insert(c1[j]); ci[x]+=k-j;
}
}
for(int i=1;i<=_d;i++) h1[hd[i]]=0; _t=0;
for(int i=head[k];i;i=next[i])
if(!vis[to[i]]) solve(to[i]);
} int main(){
File("a");
pre(); n=getint(); INF--;
for(int i=1,pos;i<n;i++){
link(getint(),getint());
w[i]=getint();
for(int j=1;pri[j]*pri[j]<=w[i];j++){
pos=0;
while(!(w[i]%pri[j]))
w[i]/=pri[j],pos^=1;
if(pos) c[tt]^=val[j];
}
if(w[i]!=1 && w[i]<maxp) c[tt]^=val[lower_bound(pri+1,pri+lp+1,w[i])-pri],w[i]=1;
if(w[i]!=1) a[++la]=w[i]; c[tt-1]=c[tt];
}
sort(a+1,a+la+1); la=unique(a+1,a+la+1)-a-1;
for(int i=1;i<=la;i++) val[i]=ra();
for(int i=1;i<n;i++)
if(w[i]>1){
c[i<<1]^=val[lower_bound(a+1,a+la+1,w[i])-a];
c[i*2-1]=c[i<<1];
}
for(int i=1;i<maxp;i++) vis[i]=0; solve(1);
printf("%lld\n",ans<<1);
return 0;
}

  这道题既然是要异或和为零,那么何必树分治呢?我们只需\(dfs\)一遍,记录每个节点到根的异或和,然后两个节点之间的异或和就可以由这两个节点到根的异或和异或得到。因为\(lca\)上面那一截会消掉……

  这已经不是第一次犯这种低级错误了,所以我在这里记录下来。代码比之前短了很多,也快了很多,感人(强行增加复杂度我就是个\(zz\))

  下面贴代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
#define maxn 100010
#define maxp 10010
#define mod 999983 using namespace std;
typedef unsigned long long llg; int pri[maxp],lp,a[maxn],la,n,w[maxn],ld;
int head[maxn],next[maxn<<1],to[maxn<<1],tt;
llg c[maxn<<1],ans,val[maxn],d[maxn];
bool vis[maxn]; int getint(){
int w=0;bool q=0;
char c=getchar();
while((c>'9'||c<'0')&&c!='-') c=getchar();
if(c=='-') c=getchar(),q=1;
while(c>='0'&&c<='9') w=w*10+c-'0',c=getchar();
return q?-w:w;
} llg ra(){return (llg)rand()*(llg)rand()+(llg)rand();}
void link(int x,int y){
to[++tt]=y;next[tt]=head[x];head[x]=tt;
to[++tt]=x;next[tt]=head[y];head[y]=tt;
} void pre(){
for(int i=2;i<maxp;i++){
if(!vis[i]) pri[++lp]=i;
for(int j=1;j<=lp && pri[j]*i<maxp;j++){
vis[pri[j]*i]=1;
if(!(i%pri[j])) break;
}
}
for(int i=1;i<=lp;i++) val[i]=ra();
} void dfs(int u,int fa,llg now){
d[++ld]=now;
for(int i=head[u],v;v=to[i],i;i=next[i])
if(v!=fa) dfs(v,u,now^c[i]);
} int main(){
File("a");
pre(); n=getint();
for(int i=1,pos;i<n;i++){
link(getint(),getint());
w[i]=getint();
for(int j=1;pri[j]*pri[j]<=w[i];j++){
pos=0;
while(!(w[i]%pri[j]))
w[i]/=pri[j],pos^=1;
if(pos) c[tt]^=val[j];
}
if(w[i]!=1 && w[i]<maxp) c[tt]^=val[lower_bound(pri+1,pri+lp+1,w[i])-pri],w[i]=1;
if(w[i]!=1) a[++la]=w[i]; c[tt-1]=c[tt];
}
sort(a+1,a+la+1); la=unique(a+1,a+la+1)-a-1;
for(int i=1;i<=la;i++) val[i]=ra();
for(int i=1;i<n;i++)
if(w[i]>1){
c[i<<1]^=val[lower_bound(a+1,a+la+1,w[i])-a];
c[i*2-1]=c[i<<1];
}
dfs(1,0,0); sort(d+1,d+ld+1);
for(int i=1,j;j=i,i<=ld;i=j+1){
while(j<ld && d[j+1]==d[i]) j++;
ans+=(llg)(j-i)*(llg)(j-i+1);
}
printf("%lld\n",ans);
return 0;
}

UOJ #192 【UR #14】 最强跳蚤的更多相关文章

  1. 【uoj#192】[UR #14]最强跳蚤 Hash

    题目描述 给定一棵 $n$ 个点的树,边有边权.求简单路径上的边的乘积为完全平方数的点对 $(x,y)\ ,\ x\ne y$ 的数目. 题解 Hash 一个数是完全平方数,当且仅当每个质因子出现次数 ...

  2. 【胡策篇】题解 (UOJ 192 + CF938G + SPOJ DIVCNT2)

    和泉纱雾与烟花大会 题目来源: UOJ 192 最强跳蚤 (只改了数据范围) 官方题解: 在这里哦~(说的很详细了 我都没啥好说的了) 题目大意: 求树上各边权乘积是完全平方数的路径数量. 这种从\( ...

  3. UOJ#192. 【UR #14】最强跳蚤

    题目链接 http://uoj.ac/problem/192 暑期课第二天 树上问题进阶 具体内容看笔记博客吧 题意 n个节点的树T 边有边权w 求满足(u, v)上所有边权乘积为完全平方数的路径有多 ...

  4. (GDOI2018模拟九)【UOJ#192】【UR#14】最强跳蚤

    (开头先Orz myh) 原题目: 在人类和跳蚤的战争初期,人们凭借着地理优势占据了上风——即使是最强壮的跳蚤,也无法一下越过那一堵坚固的城墙. 在经历了惨痛的牺牲后,跳蚤国王意识到再这样下去,跳蚤国 ...

  5. uoj192 【UR #14】最强跳蚤

    题目 和成爷达成一致,被卡随机的话就是过了 考虑一个完全平方数的所有质因子次幂一定是偶数,于是对于每一条边我们都只保留其出现次数为奇数的质因子 注意到有一个点的\(w\leq 80\),于是考虑状压质 ...

  6. UOJ 【UR #5】怎样跑得更快

    [UOJ#62]怎样跑得更快 题面 这个题让人有高斯消元的冲动,但肯定是不行的. 这个题算是莫比乌斯反演的一个非常巧妙的应用(不看题解不会做). 套路1: 因为\(b(i)\)能表达成一系列\(x(i ...

  7. UOJ192 最强跳蚤

    题目链接 problem 给出一个n个点带边权的树,问有多少对\((u,v)\)满足\(u\)到\(v\)路径上边权的乘积为完全平方数. \(n\le 10^5,w\le 10^8\) solutio ...

  8. UOJ #22 UR #1 外星人

    LINK:#22. UR #1 外星人 给出n个正整数数 一个初值x x要逐个对这些数字取模 问怎样排列使得最终结果最大 使结果最大的方案数又多少种? n<=1000,x<=5000. 考 ...

  9. UOJ.52.[UR #4]元旦激光炮(交互 思路)

    题目链接 \(Description\) 交互库中有三个排好序的,长度分别为\(n_a,n_b,n_c\)的数组\(a,b,c\).你需要求出所有元素中第\(k\)小的数.你可以调用至多\(100\) ...

随机推荐

  1. 转:透析QTP自动化测试框架SAFFRON

    1.为什么要使用框架? 框架是一组自动化测试的规范.测试脚本的基础代码,以及测试思想.惯例的集合.可用于减少冗余代码.提高代码生产率.提高代码重用性和可维护性.例如QTestWare就是QTP自动化测 ...

  2. ThinkPHP 框架执行流程分析

    总体来说,应用的流程涉及到几个文件:Index.phpThinkPHP.phpThink.class.phpApp.class.phpDispatcher.class.phpThinkPHP/Mode ...

  3. Php和httpd.conf的配置

    http://www.cnblogs.com/homezzm/archive/2012/08/01/2618062.html http://book.51cto.com/art/201309/4096 ...

  4. C# Excel嵌入到Winform

    本文讲的这个技术是把Excel表格嵌入到自己开发程序的Form窗体中进行操作,给客户一个不用切换窗口的操作界面,似乎更好.这在VC中用OLE技术很容易实现,但是在C#中方法就不一样啦.下面将就此进行阐 ...

  5. php报错 Call to undefined function mb_stripos()

    错误原因 没有mbstring扩展 本文只介绍Linux解决办法 方法一 编译PHP的时候 带上--enable-mbstring参数 方法二 进入PHP源码/ext/mbstring目录 ./con ...

  6. 静态NAT、动态NAT

    静态NAT.动态NAT 实验拓扑: 实验目的:熟悉网络地址转换协议 掌握静态NAT 和动态NAT的配置 分析静态NAT 和动态NAT的区别 使用show命令来检查NAT的运行情况 实验要求:按拓扑图来 ...

  7. XML 从基础到精通

    1.简介 XML(可扩展标记语言)语言是一种数据交换标准,用于存储数据:关键词是标记: XML具有以下优点: (1) 方便的穿过防火墙,在不同的操作系统之间通信,跨语言,跨平台.数据共享非常方便.(J ...

  8. 功能强大的HTML

    HTML基本标签(一) 1.什么是HTML html:Hyper TextMakeup language:超文本标记语言 html:网页的“源码” 浏览器:“解释和执行”html源码的工具 2.网页的 ...

  9. tabBar自定义

    有时系统的tabBar并不能满足我们的开发需求: 这时,我们需要自定义一个tabBar.直接上代码: // 在tabBarController中用KVC更换掉系统tabBar [self setVal ...

  10. n皇后问题<dfs>

    n皇后问题指的是: n*n的国际象棋棋盘上摆放n个皇后,使其不能互相攻击, 即任意两个皇后都不能处于同一行.同一列或同一斜线上, 问有多少种摆法. 和一般n皇后问题不同的是,现在棋盘上有可能已经放了一 ...