牛客网字节跳动冬令营网络赛J Sortable Path on Tree —— 点分治
题目:https://ac.nowcoder.com/acm/contest/296/J
用点分治;
记录了值起伏的形态,二元组 (x,y) 表示有 x 个小于号,y 个大于号;
因为小于号和大于号都 >=2 就不合法了,所以状态是 3×3 的;
然后根据各种形态拼接...写了一晚上,最后连最简单的样例都过不了了...
感觉似乎走入歧途了,这样讨论太麻烦...
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
typedef long long ll;
int const xn=1e5+,inf=1e9;
int n,hd[xn],ct,to[xn<<],nxt[xn<<],w[xn],siz[xn],rt,mx,sum,wmx;
ll ans,b[][][xn];
bool vis[xn];
struct N{
int x,y,v;
N(int x=,int y=,int v=):x(x),y(y),v(v) {}
};
vector<N>tmp;
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void ins(int x,int y,int p){for(;p<=wmx;p+=(p&-p))b[x][y][p]++;}
int query(int x,int y,int p){int ret=; for(;p;p-=(p&-p))ret+=b[x][y][p]; return ret;}
int upquery(int x,int y,int p){return query(x,y,wmx)-query(x,y,p-);}
void getrt(int x,int fa)
{
siz[x]=; int nmx=;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa)continue;
getrt(u,x); siz[x]+=siz[u];
if(siz[u]>nmx)nmx=siz[u];
}
nmx=max(nmx,sum-siz[x]);
if(nmx<mx)mx=nmx,rt=x;
}
void update(int t1,int t2,int a1)
{
if(t1==&&t2==)ans+=query(,,wmx)+query(,,wmx)+query(,,wmx)+query(,,wmx)+query(,,wmx)+upquery(,,a1)+query(,,a1),ans++;
//--\ , --/ , --__ , --`` , --``__ , --.\ , --/.
if(t1==&&t2==)ans+=query(,,a1)+query(,,wmx)+query(,,wmx)+query(,,wmx)+upquery(,,a1)+upquery(,,a1),ans++;
//--__/ , ``--\ , --__-- , ``--__ , ``--__`` , ``--\`
if(t1==&&t2==)ans+=query(,,wmx)+query(,,wmx)+upquery(,,a1)+upquery(,,a1)+upquery(,,a1),ans++;//``\--\ , ``\--__ , --\__`` , ``\--__`` , ``\.`
if(t1==&&t2==)ans+=query(,,a1)+query(,,wmx)+upquery(,,a1)+query(,,wmx)+query(,,a1)+query(,,a1),ans++;
//__``-- , __--/ , __-- \ , __--`` , __--``__ , __--``.
if(t1==&&t2==)ans+=query(,,a1)+query(,,a1)+upquery(,,a1)+upquery(,,a1),ans++;//--``__-- , --``__/ , --__``-- , --__``\ if(t1==&&t2==)ans+=upquery(,,a1)+upquery(,,a1),ans++;//.\--__ , .\--\
if(t1==&&t2==)ans+=query(,,wmx)+query(,,a1)+query(,,wmx)+query(,,a1)+query(,,a1),ans++;// // , /``__ , /--`` , /--``__ , /`.
if(t1==&&t2==)ans+=query(,,a1)+query(,,a1),ans++;// /.--`` , /./
}
void dfs(int x,int fa,int s1,int s2)//to rt
{
if(w[x]<w[fa])s1++; if(w[x]>w[fa])s2++;
if((s1>=&&s2==&&w[rt]>w[x])||(s1==&&s2>=&&w[rt]<w[x]))return;//&&
int t1=min(s1,),t2=min(s2,);
ans+=query(,,wmx); update(t1,t2,w[x]);
//printf("x=%d ans=%lld t1=%d t2=%d\n",x,ans,t1,t2);
tmp.pb(N(t2,t1,w[x]));
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=fa&&!vis[u])dfs(u,x,s1,s2);
}
/*
void update2(int t1,int t2,int a1)
{
if(t1==0&&t2==0)ans+=query(0,1,wmx)+query(0,2,wmx)+query(1,0,wmx)+query(1,1,wmx)+query(2,0,mx),ans++;//--__ , --\__ , --`` , --``__ , --/
if(t1==0&&t2==1)ans+=query(0,2,wmx)+query(1,0,wmx)+query(2,0,a1)+query(0,1,wmx),ans++;//``\--__ , __--__ , /``__ , ``--__
if(t1==0&&t2==2)ans+=query(0,1,wmx)+query(0,2,wmx)+query(1,0,a1),ans++;//``--\ , ``\--\ , __``\
if(t1==1&&t2==0)ans+=query(0,1,wmx)+query(0,2,a1)+query(1,0,wmx)+upquery(1,1,a1)+query(2,0,wmx),ans++;//--__-- , --\__`` , __--`` , --``__-- , /--``
if(t1==1&&t2==1)ans+=upquery(1,0,a1)+upquery(2,0,a1),ans++;//__--``__ , /--``__
if(t1==2&&t2==0)ans+=query(0,1,a1)+query(1,0,wmx)+upquery(1,1,a1)+query(2,0,wmx),ans++;//--__/ , __--/ , --``__/ , //
}
void dfs2(int x,int fa,int s1,int s2)//from rt
{
if(w[x]<w[fa])s2++; if(w[x]>w[fa])s1++;
if((s1>=2&&s2==1)||(s1==1&&s2>=2))return;
int t1=min(s1,2),t2=min(s2,2);
ans+=query(0,0,wmx); update2(t1,t2,w[x]);
tmp.pb(N(t1,t2,w[x]));
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=fa&&!vis[u])dfs2(u,x,s1,s2);
}
*/
void work(int x,int ss)
{
printf("x=%d\n",x);
vis[x]=;//
memset(b,,sizeof b);
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
dfs(u,x,,);
printf("u=%d\n",u);
for(int j=;j<tmp.size();j++){ins(tmp[j].x,tmp[j].y,tmp[j].v);
printf("t(%d,%d,%d)\n",tmp[j].x,tmp[j].y,tmp[j].v);}
printf("ans=%lld\n",ans);
tmp.clear();
}
/* //无序
memset(b,0,sizeof b);
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
dfs2(u,x,0,0);
for(int j=0;j<tmp.size();j++)ins(tmp[j].x,tmp[j].y,tmp[j].v);
tmp.clear();
}
*/
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
sum=(siz[u]>siz[x]?ss-siz[x]:siz[x]); mx=inf;
getrt(u,); work(u,sum);//(u,0)
}
}
int main()
{
int T=rd();
while(T--)
{
n=rd();
ct=; memset(hd,,sizeof hd); wmx=;
memset(vis,,sizeof vis);
for(int i=;i<=n;i++)w[i]=rd(),wmx=max(wmx,w[i]);
for(int i=,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);
sum=n; mx=inf; getrt(,);//
ans=; work(rt,sum);
printf("%lld\n",ans+n);//
}
return ;
}
艰难尝试
然后看了看AC代码,也有一篇拼形态的,看了半天没看懂...
其实应该是不用拼形态的,直接考虑拼起来以后的大于号、小于号情况来判断是否对两个端点的值有要求;
如果拼起来以后是 (0,~) 或 (~,0) 或 (1,1),那么对前后端点值的大小是没有限制的;
如果是 (1,~),小于号只有一个,那么一定是两个下降的段,要求前端的值 <= 后端的值,才可以从小于号的地方断开,成为有序的;
如果是 (~,1),大于号只有一个,同理,前端的值 >= 后端的值;
所以只要考虑拼完以后的形态就可以了,讨论变得简单许多;
注意判掉不合法的情况,而且每个点自己单独也是一种合法的情况;
清空树状数组时不要暴力使复杂度剧增,可以再 dfs 一遍,把刚才加上的减去;
可以对值域先离散化,加快树状数组的查询;
注意点分治不要写错;
注意本题没有对 1e9+7 取模呵呵。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
typedef long long ll;
int const xn=1e5+,inf=1e9;
int n,hd[xn],ct,to[xn<<],nxt[xn<<],w[xn],siz[xn],mx,sum,rt,wmx,b[][][xn];
ll ans;
bool vis[xn];
struct N{
int u,v,w;
N(int u=,int v=,int w=):u(u),v(v),w(w) {}
};
vector<N>tmp;
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return f?ret:-ret;
}
void add(int x,int y){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct;}
void ins(int x,int y,int p,int v){for(;p<=wmx;p+=(p&-p))b[x][y][p]+=v;}
int query(int x,int y,int p){if(!p)return ; int ret=; for(;p;p-=(p&-p))ret+=b[x][y][p]; return ret;}
int upquery(int x,int y,int p){return query(x,y,wmx)-query(x,y,p-);}
void getrt(int x,int fa)
{
siz[x]=; int nmx=;
for(int i=hd[x],u;i;i=nxt[i])
{
if((u=to[i])==fa||vis[u])continue;
getrt(u,x); siz[x]+=siz[u];
if(nmx<siz[u])nmx=siz[u];
}
nmx=max(nmx,sum-siz[x]);
if(nmx<mx)mx=nmx,rt=x;
}
void update(int s1,int s2,int w)
{
ans++;
for(int i=;i<=;i++)
for(int j=;j<=;j++)
{
int t1=s1+i,t2=s2+j;
if(t1>=&&t2>=)continue;
if(!t1||!t2||(t1==&&t2==))ans+=query(i,j,wmx);
else if(t1==)ans+=upquery(i,j,w);
else if(t2==)ans+=query(i,j,w);
}
}
void dfs(int x,int fa,int s1,int s2)
{
if(w[x]<w[fa])s1++; if(w[x]>w[fa])s2++;
if(s1>)s1=; if(s2>)s2=;
if((s1==&&s2==)||(s1==&&s2==&&w[x]>w[rt])||(s1==&&s2==&&w[x]<w[rt]))return;
update(s1,s2,w[x]); tmp.pb(N(s1,s2,w[x]));
//printf("x=%d s1=%d s2=%d ans=%d\n",x,s1,s2,ans);
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=fa&&!vis[u])dfs(u,x,s1,s2);
}
void clear(int x,int fa,int s1,int s2)
{
if(w[x]<w[fa])s1++; if(w[x]>w[fa])s2++;
if(s1>)s1=; if(s2>)s2=;
if((s1==&&s2==)||(s1==&&s2==&&w[x]>w[rt])||(s1==&&s2==&&w[x]<w[rt]))return;
ins(s2,s1,w[x],-);
for(int i=hd[x],u;i;i=nxt[i])
if((u=to[i])!=fa&&!vis[u])clear(u,x,s1,s2);
}
void work(int x,int ss)
{
//printf("x=%d\n",x);
vis[x]=;
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
dfs(u,x,,); int siz=tmp.size();
for(int j=;j<siz;j++)ins(tmp[j].v,tmp[j].u,tmp[j].w,);
tmp.clear();
}
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
clear(u,x,,);
}
for(int i=hd[x],u;i;i=nxt[i])
{
if(vis[u=to[i]])continue;
sum=(siz[u]>siz[x]?ss-siz[x]:siz[u]);//siz[u]!
mx=inf; getrt(u,); work(rt,sum);
}
}
int tt[xn];
int main()
{
int T=rd();
while(T--)
{
n=rd();
ct=; for(int i=;i<=n;i++)hd[i]=;
for(int i=;i<=n;i++)w[i]=rd(),tt[i]=w[i];
sort(tt+,tt+n+); wmx=unique(tt+,tt+n+)-tt-;
for(int i=;i<=n;i++)w[i]=lower_bound(tt+,tt+wmx+,w[i])-tt;
for(int i=,x,y;i<n;i++)x=rd(),y=rd(),add(x,y),add(y,x);
ans=; for(int i=;i<=n;i++)vis[i]=;
mx=inf; sum=n; getrt(,); work(rt,n);
printf("%lld\n",ans+n);
}
return ;
}
牛客网字节跳动冬令营网络赛J Sortable Path on Tree —— 点分治的更多相关文章
- 字节跳动冬令营网络赛 D.The Easiest One(贪心 数位DP)
题目链接 \(x:\ 11010011\) \(y:\ 10011110\) (下标是从高位往低位,依次是\(1,2,...,n\)) 比如对于这两个数,先找到最高的满足\(x\)是\(0\),\(y ...
- 字节跳动冬令营网络赛 Solution
A:Aloha Unsolved. B:Origami Unsolved. 题意: 初始的时候有一张纸,可以从左边往右边折叠,或者从右边往左边折叠 每次折叠的长度不能超过现有宽度,最后折叠到长度为1 ...
- 计蒜客 2019南昌邀请网络赛J Distance on the tree(主席树)题解
题意:给出一棵树,给出每条边的权值,现在给出m个询问,要你每次输出u~v的最短路径中,边权 <= k 的边有几条 思路:当时网络赛的时候没学过主席树,现在补上.先树上建主席树,然后把边权交给子节 ...
- 牛客网多校第4场 J Hash Function 【思维+并查集建边】
题目链接:戳这里 学习博客:戳这里 题意: 有n个空位,给一个数x,如果x%n位数空的,就把x放上去,如果不是空的,就看(x+1)%n是不是空的. 现在给一个已经放过数的状态,求放数字的顺序.(要求字 ...
- 牛客网多校训练第一场 J - Different Integers(树状数组 + 问题转换)
链接: https://www.nowcoder.com/acm/contest/139/J 题意: 给出n个整数的序列a(1≤ai≤n)和q个询问(1≤n,q≤1e5),每个询问包含两个整数L和R( ...
- 牛客网多校第7场 J Sudoku Subrectangles 【构造】
题目:戳这里 题意:给一个n*m的矩阵,里面由a~z及A~Z构成,问有多少个子矩阵满足任意一行或一列中都没有相同的字母. 解题思路:左上角和右下角两点可以确定一个矩阵.可以先预处理出来每个点作为一个矩 ...
- 南昌网络赛J. Distance on the tree 树链剖分+主席树
Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...
- 2019南昌邀请赛网络赛:J distance on the tree
1000ms 262144K DSM(Data Structure Master) once learned about tree when he was preparing for NOIP(N ...
- 南昌网络赛J. Distance on the tree 树链剖分
Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...
随机推荐
- [转]jquery中innerWidth(),outerWidth(),outerWidth(true)和width()的区别
转自:http://www.cnblogs.com/keyi/p/5933981.html jquery中innerWidth(),outerWidth(),outerWidth(true)和wi ...
- ArcGIS API for js Legend(图例)
1.说明 有关怎么把ArcGIS API for js部署到IIS上,请参考我上面的写的博客https://www.cnblogs.com/net064/p/10302660.html 2.运行效果 ...
- UITableView 右侧索引
1.设置右侧索引字体颜色 self.tabView.sectionIndexColor = [UIColor blackColor]; 2.设置右侧索引背景色 self.cityTabView.sec ...
- linux 中解压与压缩 常用操作详细讲解
平时有时候 会在服务器进行一些文件的操作,比如安装一些服务与软件等等,都有解压操作,一般在 导出一些简单的服务器文件,也是先压缩后再导出,因此,在这里根据平时用到解压与压缩命令的频率来记录下: 1.最 ...
- 用cocos2d-html5做的消除类游戏《英雄爱消除》(3)——游戏主界面
游戏主界面,同时也是主程序,包括sprite的生成加入以及游戏状态的控制. 下面同样贴下源码再讲解; /** * Power by html5中文网(html5china.com) * author: ...
- Block的详细介绍
关于block的介绍 ==ios中的内存空间分级== 栈区 存放函数参数值.局部变量.函数返回地址等,函数跳转跳转时现场保护(寄存器),这些系统都会帮我们自动实现,无需我们干预. 所以大量的局部变量, ...
- 数据库基本表创建 完整性约束 foreign Key
理解以下几张表的内容,根据实际情况设计属性名.数据类型.及各种完整性约束(primary key.foreign key.not null.unique.check),用数据定义语言实现,然后设计实验 ...
- 最短路N题Tram SPFA
#include <algorithm>#include <queue>#include <cstdio>#include <cstdlib>#inc ...
- ELK初步指南
ELK的简单科普文章,加入了自己的一些理解. 内容包括ELK的基本介绍, 应用场景, 架构设计, 监控及自监控, 业界进展及推荐资料等. 用户故事 场景一 作为一个运维工程师, 某天虚拟机出现故障, ...
- LINQ 学习路程 -- 查询语法 LINQ Query Syntax
1.查询语法 Query Syntax: from <range variable> in <IEnumerable<T> or IQueryable<T> ...