题目传送门(内部题21)


输入格式

第一行一个字符串$str$,表示数据类型。
第二行一个正整数$k$,表示集合$K$的大小,保证$k>1$。
接下来$k$行每行$k$个数,第$i$行第$j$个数表示$i\oplus j$的值,数据保证满足上文所提到的运算律。
接下来一行一个正整数$n$,表示城市的总数。
接下来$n-1$行,每行三个数$u,v,c$表示在城市$u$和城市$v$之间有一条边权为$c$的道路。
接下来一行$n$个数,第$i$个数表示城市$i$的敌对城市$x_i$,若$x_i=0$表示第$i$座城市非常热爱和平,否则保证有$x_{x_i}=i$。


输出格式

输出共一行,表示所有路径的旅者最终手上的数之和。


样例

样例输入:

F
2
0 1
1 0
4
1 2 1
2 3 1
2 4 0
0 0 4 3

样例输出:

6


数据范围与提示


题解

从$8$月$23$号打到$11$月$6$号,一有空就打,终于$AC$了(同桌疯狂吐槽我菜我也没办法……

怎么改出来的我已经不清楚了,根挤牙膏似的……

先转化一下题意:

在一棵$n$个节点的树上有一些坏点对,树上的边有边权,定义一种交换群运算,求所有不含坏点对的路径上的边权依次进行运算后的结果的和。

保证坏点对在以$1$为根的树上无父子关系。

由于题目保证了互相影响的点对一定没有父子关系,因此我们如果有了一条路径,只要$dfs$其中的一边判断另一边是否有这个点就行了。

因此我们对每个点$dfs$遍历每个轻儿子,因为求出了$dfs$序所以每个子树是一段连续的区间。我们$ban$掉一个点相当于$ban$掉了它的整个子树,因此我们访问到一个点就用线段树将这个区间的答案置$0$,因为逆元存在,对于每个点统计到所有可达的在已经访问的子树中的点到根的运算值即可。

原本的做法需要使用区间覆盖,考虑树的子树区间肯定只会互相包含或互不相交,实际上每次被删去的都是一些完整的区间。

考虑能否统计每个区间被减去了多少次。假设当前统计到节点$x$,与其对应的点为$u$,那么我们从$u$开始$dfs$,如果走到一个对应$x$的祖先的点就直接不访问,这样我们就能遍历到所有删去整个$x$的子树区间的点了,当然也可能$x$和它对应的点根本不会被整个删去,这意味着$x$到$lca(x,u)$的路径上存在一个对应$u$的祖先的点,这个可以随便维护一下。

我们用总的贡献减去$ban$掉的点对对答案的贡献,我们只要能够对于每个$x$求出这样的点对数目,最后计算的过程也可以用前面的$\Theta(nk)$的做法优化。当然每对点只要选一边统计就行了。

问题可以转化为给两棵$n$个节点的树,每个标号$x$有一个$k$维向量的权$w_x$。对于所有的$x$,求出$\sum w_y$,满足$x$在第一棵树上是$y$的祖先且$y$在第二棵树上是$x$的祖先,同时在$x$和$y$之间没有合法的$y$。

在第二棵树上$dfs$,只要在第一棵树上求出相同标号点子树的贡献即可。

对于新加入的点,贡献减去其子树中所有贡献,再将最近的父亲减去其贡献即可,可以树状数组维护。

注意要用树链剖分求$LCA$,而且读入要使用$AE86$

不然就会$\downarrow$

时间复杂度:$\Theta(nk\log n)$。

期望得分:$100$分。

实际得分:$96\sim 100$分(看卡常了)。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to,w;}e[500000];
int head[200001],cnt;
char opt[5];
int n,k;
int Map[129][129],pos[129][129],f[200001][129],g[200001][129];
int a[200001];
int dp[200001],dfn[200001],end[200001],depth[200001],t[200001],fa[200001],val[200001],wzc[129],qf[129],qg[129],tim;
int top[200001],size[200001],son[200001];
int tr[200001][129],trx[200001];
bool vis[200001];
long long ans;
namespace ae86{
const int bufl=1<<20;
char buf[bufl],*s=buf,*t=buf;
inline int fetch(){
if(s==t){t=(s=buf)+fread(buf,1,bufl,stdin);if(s==t)return EOF;}
return*s++;
}
inline int read(){
int a=0,b=1,c=fetch();
while(!isdigit(c))b^=c=='-',c=fetch();
while(isdigit(c))a=a*10+c-48,c=fetch();
return b?a:-a;
}
}
using ae86::read;
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
void dfs(int x)
{
dfn[x]=++tim;
t[tim]=x;
size[x]=1;
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
fa[e[i].to]=x;
dp[e[i].to]=Map[dp[x]][e[i].w];
depth[e[i].to]=depth[x]+1;
dfs(e[i].to);
for(int j=0;j<=k;j++)f[x][Map[e[i].w][j]]+=f[e[i].to][j];
f[x][e[i].w]++;val[e[i].to]=e[i].w;
size[x]+=size[e[i].to];
if(size[e[i].to]>size[son[x]])son[x]=e[i].to;
}
end[x]=tim;
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
depth[top[x]]>depth[top[y]]?x=fa[top[x]]:y=fa[top[y]];
return depth[x]<depth[y]?x:y;
}
void dfs(int x,int topp)
{
top[x]=topp;
if(son[x])dfs(son[x],topp);
for(int i=head[x];i;i=e[i].nxt)if(!top[e[i].to])dfs(e[i].to,e[i].to);
}
void add(int x,int res)
{
for(int i=x;i<=n;i+=i&-i)
for(int j=0;j<=k;j++)
tr[i][j]+=g[res][j];
}
void del(int x,int res)
{
for(int i=x;i<=n;i+=i&-i)
for(int j=0;j<=k;j++)
tr[i][j]-=g[res][j];
}
void add(int x){for(int i=x;i<=n;i+=i&-i)trx[i]++;}
void del(int x){for(int i=x;i<=n;i+=i&-i)trx[i]--;}
int ask(int x){int res=0;for(int i=x;i;i-=i&-i)res+=trx[i];return res;}
void askf(int x)
{
for(int i=x;i;i-=i&-i)
for(int j=0;j<=k;j++)
wzc[j]+=tr[i][j];
}
void askr(int x)
{
for(int i=x;i;i-=i&-i)
for(int j=0;j<=k;j++)
wzc[j]-=tr[i][j];
}
void get(int res1,int res2,int x)
{
int fail1=0,fail2=0;
int res=Map[dp[x]][dp[x]];
for(int i=0;i<=k;i++)
{
if(f[res1][i])qf[++fail1]=i;
if(g[res2][i])qg[++fail2]=i;
}
for(int i=1;i<=fail1;i++)
for(int j=1;j<=fail2;j++)
ans-=1LL*f[res1][qf[i]]*g[res2][qg[j]]*pos[Map[qf[i]][qg[j]]][res];
}
void get(int x)
{
int y=a[x];
if(y)
{
if(ask(dfn[y]))vis[x]=1;
else
{
memset(wzc,0,sizeof(wzc));
askf(end[y]);
askr(dfn[y]-1);
for(int i=0;i<=k;i++)g[y][i]=f[y][i]-wzc[i];
get(x,y,LCA(x,y));
add(dfn[y],y);
del(end[y]+1);
add(dfn[y]);
}
}
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x])get(e[i].to);
if(!vis[x]&&a[x])
{
del(dfn[a[x]],a[x]);
add(end[a[x]]+1);
del(dfn[a[x]]);
}
}
int main()
{
scanf("%s",opt+1);
k=read()-1;
int now=-1;
for(int i=0;i<=k;i++)
for(int j=0;j<=k;j++)
{
Map[i][j]=read();
pos[Map[i][j]][i]=j;
}
for(int i=0;i<=k;i++)
{
now=i;
for(int j=0;j<=k;j++)
if(Map[i][j]!=j){now=-1;break;}
if(now>=0)break;
}
n=read();
for(int i=1;i<n;i++)
{
int u=read(),v=read(),c=read();
add(u,v,c);
add(v,u,c);
}
for(int i=1;i<=n;i++)a[i]=read();
dp[1]=now;
depth[1]=1;
dfs(1);dfs(1,1);
for(int i=0;i<=k;i++)
{
g[1][i]=f[1][i];
ans+=1LL*g[1][i]*i;
}
for(int i=2;i<=n;i++)
{
int x=t[i];
int fat=fa[x];
int v=val[x];
for(int j=0;j<=k;j++)g[fat][Map[v][j]]-=f[x][j];
g[fat][v]--;
for(int j=0;j<=k;j++)g[x][j]=f[x][j]+g[fat][pos[j][v]];
g[x][v]++;
for(int j=0;j<=k;j++){g[fat][Map[v][j]]+=f[x][j];ans+=1LL*g[x][j]*j;}
g[fat][v]++;
}
for(int i=2;i<=n;i++)
{
f[i][now]++;
for(int j=0;j<=k;j++)g[i][Map[dp[i]][j]]=f[i][j];
for(int j=0;j<=k;j++)f[i][j]=g[i][j];
}
get(1);
printf("%lld",ans);
return 0;
}

rp++

[CSP-S模拟测试]:异或(树状数组+LCA)的更多相关文章

  1. [CSP-S模拟测试]:柱状图(树状数组+二分+三分)

    题目描述 $WTH$获得了一个柱状图,这个柱状图一共有$N$个柱子,最开始第$i$根柱子的高度为$x_i$,他现在要将这个柱状图排成一个屋顶的形状,屋顶的定义如下:$1.$屋顶存在一个最高的柱子,假设 ...

  2. [CSP-S模拟测试]:影魔(树状数组+线段树合并)

    题目背景 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个灵魂,都有着自己 ...

  3. [CSP-S模拟测试]:统计(树状数组+乱搞)

    题目传送门(内部题120) 输入格式 第一行,两个正整数$n,m$. 第二行,$n$个正整数$a_1,a_2,...,a_n$,保证$1\leqslant a_i\leqslant n$,可能存在相同 ...

  4. BZOJ 4017 小 Q 的无敌异或 ( 树状数组、区间异或和、区间异或和之和、按位计贡献思想 )

    题目链接 题意 : 中文题 分析 : 首先引入两篇写的很好的题解 题解一.题解二 听说这种和异或相关区间求和的问题都尽量按位考虑 首先第一问.按二进制位计贡献的话.那么对于第 k 位而言 其贡献 = ...

  5. 【BZOJ2819】Nim 树状数组+LCA

    [BZOJ2819]Nim Description 著名游戏设计师vfleaking,最近迷上了Nim.普通的Nim游戏为:两个人进行游戏,N堆石子,每回合可以取其中某一堆的任意多个,可以取完,但不可 ...

  6. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  7. HDU4836 The Query on the Tree(树状数组&&LCA)

    由于智力的问题,百度之星完全lu不动..开场看第一题根据题目给的条件我觉得一定是可以构造出来的,题目给的意思颇有鸽巢原理的感觉,于是觉得开场第一题应该就是智力构造题了,想了半个小时,发现完全想不动,于 ...

  8. BZOJ3881[Coci2015]Divljak——AC自动机+树状数组+LCA+dfs序+树链的并

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  9. HDU 5293 Annoying problem 树形dp dfs序 树状数组 lca

    Annoying problem 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 Description Coco has a tree, w ...

随机推荐

  1. JSP 定义行列数表单创建表格

    1.添加行数 .列数提交表单 <!doctype html> <html> <head> <title>setTable-发送表单</title& ...

  2. JS基础(上)

    JS与DOM的关系 浏览器有渲染html代码的功能,把html源码(如div,p标签等)在内存里形成一个DOM对象 文档对象模型DOM(Document Object Model)定义访问和处理HTM ...

  3. 《JAVA设计模式》之组合模式(Composite)

    在阎宏博士的<JAVA与模式>一书中开头是这样描述合成(Composite)模式的: 合成模式属于对象的结构模式,有时又叫做“部分——整体”模式.合成模式将对象组织到树结构中,可以用来描述 ...

  4. Shell脚本语言学习总结

    Shell 是一种脚本程序,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了. 编写第一个Shell 程序 在linux命令行执行 [root@iz2zeexr9tk4ckr7dp ...

  5. 2019 Multi-University Training Contest 1 - 1004 - Vacation - 二分 - 思维

    http://acm.hdu.edu.cn/showproblem.php?pid=6581 一开始想了好几个假算法.但是启发了一下潘哥,假如时间知道的话就可以从头开始确定各个车的位置.那么直接 \( ...

  6. Codeforces Round #529 (Div. 3) E. Almost Regular Bracket Sequence (思维)

    Codeforces Round #529 (Div. 3) 题目传送门 题意: 给你由左右括号组成的字符串,问你有多少处括号翻转过来是合法的序列 思路: 这么考虑: 如果是左括号 1)整个序列左括号 ...

  7. C#Contains方法的错误理解

    一,我们先看看代码: string aa = "1,2,3,44"; "; "); "); Console.WriteLine("a输出&q ...

  8. 二进制部署k8s

    一.二进制部署 k8s集群 1)参考文章 博客: https://blog.qikqiak.com 文章: https://www.qikqiak.com/post/manual-install-hi ...

  9. idea 2019.1.3最新注册码

    CATF44LT7C-eyJsaWNlbnNlSWQiOiJDQVRGNDRMVDdDIiwibGljZW5zZWVOYW1lIjoiVmxhZGlzbGF2IEtvdmFsZW5rbyIsImFzc ...

  10. php中的花括号使用详解

    1.简单句法规则(用花括号界定变量名,适用于PHP所有版本,是php系统设定):    $a = 'flower';    echo "She received some $as" ...