题目: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. Conductors(水题)

    Conductors Background Everyone making translations from English to Russian knows an English phrase & ...

  2. 记录-移动端网页触摸内容滑动js插件

    需求: 在webapp中需要左右滑动手机,移动主页的轮播图.也可用在引导页(欢迎页)的大图左右滑动 可用: 百度:swiper插件 在项目中导入插件,这里只有部分代码,具体百度swiper <l ...

  3. polynomial time

    https://en.wikipedia.org/wiki/Time_complexity#Polynomial_time An algorithm is said to be of polynomi ...

  4. Bootstrap 第一天

    Bootstrap第一天 1.什么是Bootstrap?     Bootstrap是由两位设计开发的.     Bootstrap主要是前端的框架(HTML.CSS.JS). 2.为什么使用Boot ...

  5. 找到最大或最小的N个值

    对于python原生的数据类型来说,并不存在直接的方法可以找到最大或最小的N个值, 传统的方法必须先排序,然后再截取相应的值,而且对于集合这类数据类型来说还不能直接排序, 需要先转化为列表才行,有的时 ...

  6. 有关java之反射的使用

    1 public class Demo02 { 2 @SuppressWarnings("all") 3 public static void main(String[] args ...

  7. 全自动安装mongoDB数据库的shell脚本

    最近在研究mongoDB数据库,写了个全自动安装mongoDB数据库的shell脚本,仅供参考,欢迎拍砖,内容如下: #!/bin/bash # shell的执行选项: # -n 只读取shell脚本 ...

  8. ubuntu13.04中把ibus中的中文拼音输入设为默认

    全新的ubuntu ,先选择 下载服务器 首选项->软件和更新 选择 最佳服务器 准备工作:卸载Ubuntu默认的ibus输入法: sudo apt-get remove ibus 然后添加Fc ...

  9. C#Winform之等待窗体

    窗体主要代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ...

  10. POJ 1068 Parencodings (类似括号的处理问题)

                                                                                                    Pare ...