题目: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 —— 点分治的更多相关文章

  1. 字节跳动冬令营网络赛 D.The Easiest One(贪心 数位DP)

    题目链接 \(x:\ 11010011\) \(y:\ 10011110\) (下标是从高位往低位,依次是\(1,2,...,n\)) 比如对于这两个数,先找到最高的满足\(x\)是\(0\),\(y ...

  2. 字节跳动冬令营网络赛 Solution

    A:Aloha Unsolved. B:Origami Unsolved. 题意: 初始的时候有一张纸,可以从左边往右边折叠,或者从右边往左边折叠 每次折叠的长度不能超过现有宽度,最后折叠到长度为1 ...

  3. 计蒜客 2019南昌邀请网络赛J Distance on the tree(主席树)题解

    题意:给出一棵树,给出每条边的权值,现在给出m个询问,要你每次输出u~v的最短路径中,边权 <= k 的边有几条 思路:当时网络赛的时候没学过主席树,现在补上.先树上建主席树,然后把边权交给子节 ...

  4. 牛客网多校第4场 J Hash Function 【思维+并查集建边】

    题目链接:戳这里 学习博客:戳这里 题意: 有n个空位,给一个数x,如果x%n位数空的,就把x放上去,如果不是空的,就看(x+1)%n是不是空的. 现在给一个已经放过数的状态,求放数字的顺序.(要求字 ...

  5. 牛客网多校训练第一场 J - Different Integers(树状数组 + 问题转换)

    链接: https://www.nowcoder.com/acm/contest/139/J 题意: 给出n个整数的序列a(1≤ai≤n)和q个询问(1≤n,q≤1e5),每个询问包含两个整数L和R( ...

  6. 牛客网多校第7场 J Sudoku Subrectangles 【构造】

    题目:戳这里 题意:给一个n*m的矩阵,里面由a~z及A~Z构成,问有多少个子矩阵满足任意一行或一列中都没有相同的字母. 解题思路:左上角和右下角两点可以确定一个矩阵.可以先预处理出来每个点作为一个矩 ...

  7. 南昌网络赛J. Distance on the tree 树链剖分+主席树

    Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...

  8. 2019南昌邀请赛网络赛:J distance on the tree

    1000ms 262144K   DSM(Data Structure Master) once learned about tree when he was preparing for NOIP(N ...

  9. 南昌网络赛J. Distance on the tree 树链剖分

    Distance on the tree 题目链接 https://nanti.jisuanke.com/t/38229 Describe DSM(Data Structure Master) onc ...

随机推荐

  1. 九度OJ 1000:计算a+b

    时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:35767 解决:15660 题目描述: 求整数a,b的和. 输入: 测试案例有多行,每行为a,b的值. 输出: 输出多行,对应a+b的结果. ...

  2. Surpassing Human-Level Face Verification Performance on LFW with GaussianFace

    Face verification remains a challenging problem in very complex conditions with large variations suc ...

  3. 我的Android进阶之旅------>如何为ListView组件加上快速滑块以及修改快速滑块图像

    使用布局文件需要将android:fastScrollEnabled="true" ,如下代码所示: <ListView android:id="@+id/list ...

  4. Cordova 教程 学习步骤-从零基础开始

    Cordova的技术交流新群

  5. 从 零开始 无差错 装好nginx+PHP

    由于这两天 一直有人追问 nginx为何报错,为何php没装好啥的,大多原因是 : 1.编译与yum混合安装,导致很多包的路径不对,进而报错 2.yum源比较旧,导致 与新版本的php不匹配 3.安装 ...

  6. scala与java之间的那些事

    scala与java之间的关系,我认为可以用一句话来开头:scala来源于java,但又高于java. scala的设计者Martin Odersky就是一个JAVA控,这位牛人设计了javac和编写 ...

  7. Redis QPS测试

    1.计算qps: 1)redis发布版本中自带了redis-benchmark性能测试工具,可以使用它计算qps.示例:使用50个并发连接,发出100000个请求,每个请求的数据为2kb,测试host ...

  8. C#自己写的第一个小程序,庆祝一下

    Packages.cs using System; using System.Collections.Generic; using System.Linq; using System.Text; na ...

  9. 【leetcode刷题笔记】Remove Duplicates from Sorted List II

    Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct numb ...

  10. 0523 CSS知识点

    高级选择器分为:后代选择器.子代选择器.并集选择器.交集选择器 后代选择器 使用空格表示后代选择器.顾名思义,父元素的后代(包括儿子,孙子,重孙子) .father .item .a p{color: ...