1.相遇
(railway.cpp/c/pas)
时间限制:1s
内存限制:256MB
【问题描述】
已知我国有 n 座城市,这些城市通过 n-1 条高铁相连。且任意两个城市联通。
小 A 想从 x1 号城市出发,到 y1 号城市,小 B 想从 x2 号城市出发,到 y2 号
城市,问他们是否可能在路途中相遇(出现在同一城市)
你需要回答 m 次这样的问题。
【输入】
输入文件名为 railway.in。
第一行一个数 T(<=10),表示数据组数
对于每一组数据:
第一行两个数 n,m(1<=n,m<=100,000)
第 2~n 行,每行两个数 x,y 表示有一条铁路连接城市 x 和 y
接下来 m 行每行四个数,分别表示 x1,y1,x2,y2,表示一次询问
【输出】
输出文件名为 railway.out。
对于每次询问输出 YES 或 NO
【输入输出样例】

railway.in railway.out
1
4 2
1 2
2 3
3 4
1 2 3 4
1 4 2 3
NO
YES

【数据说明】
对于 30%的数据,n,m<=100
对于 60%的数据,n,m<=1000
对于 100%的数据,n,m<=100,000

太没意思了,树上路径求交,这已经是我近三个月做的第三次了==上次计蒜客刚考过==

考察:LCA+ 分类情况讨论

预计得分:100分

实际得分:100分

 #include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 100090 using namespace std; int n,m,T,tot,t;
int d[maxn],head[maxn],f[maxn][];
struct node{
int to,next;
}edge[maxn*]; void add(int x,int y)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
} void init()
{
queue<int>q;
q.push();d[]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(d[v]) continue;
d[v]=d[u]+;
f[v][]=u;
for(int j=;j<=t;j++)
f[v][j]=f[f[v][j-]][j-];
q.push(v);
}
}
} int lca(int x,int y)
{
if(d[x]>d[y]) swap(x,y);
for(int i=t;i>=;i--)
if(d[f[y][i]]>=d[x]) y=f[y][i];
if(x==y) return x;
for(int i=t;i>=;i--)
if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
return f[x][];
} void Clear()
{
tot=;
memset(head,,sizeof(head));
memset(d,,sizeof(d));
memset(f,,sizeof(f));
} int main()
{
freopen("railway.in","r",stdin);
freopen("railway.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
t=log2(n)+;
for(int i=;i<=n-;i++)
{
int x=,y=;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
init();
for(int i=;i<=m;i++)
{
int a=,b=,c=,e=;
scanf("%d%d%d%d",&a,&b,&c,&e);
int p=lca(a,b);
int q=lca(c,e);
if(p==q) {printf("YES\n");continue;}
else if(d[p]>d[q])
{
if(lca(p,c)==p||lca(p,e)==p) printf("YES\n");
else printf("NO\n");
}
else
{
if(lca(q,a)==q||lca(q,b)==q) printf("YES\n");
else printf("NO\n");
}
}
Clear();
}
return ;
}

AC--railway

2. 计数
(count.cpp/c/pas)
时间限制: 1s
内存限制: 256MB
【问题描述】
小 A 是一名热衷于优化各种算法的 OIER,有一天他给了你一个随机生成的 1~n 的排列, 并定
义区间[l,r]的价值为:

他想请你告诉他, 所有区间的价值的总和为多少
【输入】
输入文件名为 count.in。
第一行一个数 T(<=10), 表示数据组数
对于每一组数据:
第一行一个数 n(1<=n,m<=100,000)
第二行 n 个数 a1...an, 表示一个 1~n 的随机的排列
【输出】
输出文件名为 count.out。
对于每组数据输出一个数, 表示答案
【输入输出样例】

count.in count.out
1 4 3
2 4 1
14

【数据范围】
对于 60%的数据: n<=1000
对于 100%的数据, n<=100,000

考场上想草草n²枚举区间,然后随便找个数据结构维护下区间最值。开始是想用ST表的,但是因为不会打了,所以就只能用线段树了。

预计得分:60分

实际得分:30分

考后发现我的线段树被卡了呜呜,线段树每次查询是logn的,预处理nlogn,所以总复杂度约为O(n²logn)。理论上是可以苟过60分的,但是.......但是......听巨佬们说线段树常数巨大,于是我就被成功卡常了==考后照着写了一遍ST表,就60分了。因为ST表的预处理复杂度同样是nlogn,但是查询是O(1)的。线段树没有修改操作的时候最好不要用的...这个故事告诉我们,多掌握一些知识总是好的==。

Scape:你就是数据结构学傻了。

 #include<cstdio>
#include<algorithm>
#define M 100090 using namespace std;
typedef long long ll; int T,n;
int seq[M];
ll ans;
struct SegmentTree{
int l,r;
int maxn,minn;
}t[M*]; void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].maxn=seq[l];
t[p].minn=seq[l];
return ;
}
int mid=(l+r)>>;
build(p*,l,mid);
build(p*+,mid+,r);
t[p].maxn=max(t[p*].maxn,t[p*+].maxn);
t[p].minn=min(t[p*].minn,t[p*+].minn);
} int ask1(int p,int l,int r)
{
if(t[p].l==l&&t[p].r==r) return t[p].maxn;
int mid=(t[p].l+t[p].r)>>;
if(l>mid) return ask1(p*+,l,r);
else if(r<=mid) return ask1(p*,l,r);
else return max(ask1(p*,l,mid),ask1(p*+,mid+,r));
} int ask2(int p,int l,int r)
{
if(t[p].l==l&&t[p].r==r) return t[p].minn;
int mid=(t[p].l+t[p].r)>>;
if(l>mid) return ask2(p*+,l,r);
else if(r<=mid) return ask2(p*,l,r);
else return min(ask2(p*,l,mid),ask2(p*+,mid+,r));
} int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&seq[i]);
build(,,n);
for(int i=;i<=n;i++)
for(int j=i;j<=n;j++)
{
if(i==j) continue;
int qwq=ask1(,i,j);
int orz=ask2(,i,j);
ans+=qwq-orz;
//printf("i:=%d j:=%d %d %d\n",i,j,qwq,orz);
}
printf("%lld\n",ans);
ans=;
//需不需要清空呢233好慌啊233
}
return ;
}

考前--30pts count

 #include<cstdio>
#include<algorithm>
#include<cmath> using namespace std;
typedef long long ll; int T,n;
ll ans;
int fa[][],fb[][]; int sta(int l,int r)
{
int k=log2(r-l+);
return max(fa[l][k],fa[r-(<<k)+][k]);
} int stb(int l,int r)
{
int k=log2(r-l+);
return min(fb[l][k],fb[r-(<<k)+][k]);
} int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&fa[i][]),fb[i][]=fa[i][];
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=n;i++)
fa[i][j]=max(fa[i][j-],fa[i+(<<(j-))][j-]);
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=n;i++)
fb[i][j]=min(fb[i][j-],fb[i+(<<(j-))][j-]);
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
ans+=sta(i,j)-stb(i,j);
printf("%lld\n",ans);
ans=;
}
return ;
}

考后--60pts count

正解1(By Chemist):分治

我们考虑题目中给出的式子:

我们可以转化为求所有区间中的最大值,将他们相加;再求出所有区间的最小值,把答案减去他们。

我们考虑找到一个区间中最大值的位置,然后以这个位置为界把区间分成两部分。那么这部分这个最大值作为区间最大值的区间个数就是这个值左边的元素个数x右边的元素个数(可能有点绕qwq)

最小值同理。

之后我们递归求解 ,就能完美地覆盖所有的区间。

枚举区间的最坏复杂度可达到O(n)(据算法作者所述),但是开始Chemist用的是O(n)找区间最值,优化可用st表降低复杂度,但是st表优化的情况只适用于给出的序列互异的情况(是一个排列),因为st表是不能记录位置的,我们需要另开一个数组来映射每个唯一元素的唯一位置。

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M=1e5+;
int n,T,fa[M][],fb[M][],pos[M];
ll ans;
int sta(int l,int r)
{
int k=log2(r-l+);
return max(fa[l][k],fa[r-(<<k)+][k]);
} int stb(int l,int r)
{
int k=log2(r-l+);
return min(fb[l][k],fb[r-(<<k)+][k]);
} void divide1(int l,int r)
{
if(l>r)return;
int mx=,p=;
mx=sta(l,r);
p=pos[mx];
ans+=(ll)mx*(p-l+)*(r-p+);
divide1(l,p-);
divide1(p+,r);
}
void divide2(int l,int r)
{
if(l>r)return;
int mn=1e9,p=;
mn=stb(l,r);
p=pos[mn];
ans-=(ll)mn*(p-l+)*(r-p+);
divide2(l,p-);
divide2(p+,r);
}
int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&fa[i][]),fb[i][]=fa[i][],pos[fa[i][]]=i;
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=n;i++)
fa[i][j]=max(fa[i][j-],fa[i+(<<(j-))][j-]);
for(int j=;j<=;j++)
for(int i=;i+(<<j)-<=n;i++)
fb[i][j]=min(fb[i][j-],fb[i+(<<(j-))][j-]);
divide1(,n);
divide2(,n);
printf("%lld\n",ans);
ans=;
memset(fa,,sizeof(fa));
memset(fb,,sizeof(fb));
}
return ;
}

Chemist--AC count

正解2(By miku_sama):单调栈

先%一手炸鲨鱼

维护两个栈:一个保存单调递增的,一个保存单调递减的,大体思路同Chemist.我们每加入一个数,就证明当前的栈顶作最大值的日子到头了==。所以我们加上他所作出的贡献。

结构体里的权值要用longlong,很玄学。

 #include<cstdio>
#include<algorithm>
#define maxn 100090 using namespace std;
typedef long long ll; int T,n;
int a[];
ll rmax,rmin;
struct sta{
int pos;ll val;
}mx[maxn],mi[maxn]; int main()
{
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
int maxhead=,minhead=;
mx[maxhead].pos=,mx[maxhead].val=1e9;
mi[minhead].pos=,mi[minhead].val=-;
for(int i=;i<=n;i++)
{
while(mx[maxhead].val<a[i]) rmax+=mx[maxhead].val*(i-mx[maxhead].pos)*(mx[maxhead].pos-mx[maxhead-].pos),maxhead--;
mx[++maxhead]=(sta){i,a[i]};
while(mi[minhead].val>a[i]) rmin+=mi[minhead].val*(i-mi[minhead].pos)*(mi[minhead].pos-mi[minhead-].pos),minhead--;
mi[++minhead]=(sta){i,a[i]};
}
while(maxhead)
{
rmax+=mx[maxhead].val*(n+-mx[maxhead].pos)*(mx[maxhead].pos-mx[maxhead-].pos);
maxhead--;
}
while(minhead)
{
rmin+=mi[minhead].val*(n+-mi[minhead].pos)*(mi[minhead].pos-mi[minhead-].pos);
minhead--;
}
printf("%lld\n",rmax-rmin);
rmax=,rmin=;
}
return ;
}

***Update:大佬语:神奇之处就在于不是暴力的去找每个区间的最大和最小值,而是逆向统计有多少区间以某个数作为最大和最小值。

3.树上统计
(treecnt.c/cpp/pas)
时间限制: 1s
内存限制: 256MB
【题目描述】
给定一棵n个点的树树。
定义Tree[L,R]表示为了使得L~R号点两两连通, 最少需要选择的边的数量。

【输入格式】
第一行一个数, n表示点数(n<=100000)
接下来n-1行每行两个数, x和y, 表示一条连接x号点和y号点的边(x,y<=n)
【输出格式】
输出一个数表示答案
【输入输出样例】

treecnt.in treecnt.out
4 1
4
1 3
2 4
16

【数据范围】
对于20%的数据: n<=10
对于40%的数据: n<=300
对于60%的数据: n<=3000
对于另外20%的数据: 树呈一条链
对于100%的数据: n<=100000

心路历程:

如图,开始想用80分算法的,后来发现60分时枚举区间就需要n²,果断放弃想40分算法,枚举区间用去了n²,那么每次操作就要O(n)内完成。后来想了一想,可以求出这个区间所有点的LCA,然后枚举这个区间的所有点,暴力向上跳,借助求LCA的遗产f数组可以到他的父亲,就还可以dfs一遍记录树上这个节点的前驱编号。(考试时想出了无向边记录一次的方法,感觉很资瓷)。这就O(n)了。区间内所有点的LCA可以预处理求出来,复杂度有保障了。

敲完距考试结束还有大概15分钟的样子,去想链的做法。还是比较好想的,只不过不知道如何判是不是链的情况,根据阅读理解数据范围描述,猜测应该n在3000左右。链时就把它处理成序列,这个节点本应在以它编号作为下标的位置上,现在不是了,用数组记录一下,然后暴力找到一条链的端点(用度数判,暴力获得每个点的相对位置),再用线段树(?)维护下最值(找区间蔓延的最远地方)。

后来开空间时有些晕了,好像会MLE的样子,不管了到时间了,20分(应该)能拿到吧....

预计得分:60分

实际得分:40分

cena上链的情况栈溢出了,luogu上是MLE了,可怜我198行代码了qwq。不过暴力打成这样就海星了。

 #include<cstdio>
#include<algorithm>
#include<queue>
#include<cstring>
#include<cmath>
#define maxnn 100090 using namespace std;
typedef long long ll; int n,tot,lim,root;
ll ans;
int head[],pre[];
int f[][],d[maxnn],lca[][];
int du[maxnn];
bool vis[maxnn];
struct node{
int to,next;
}edge[maxnn*];// 改一下范围 迁就一下链的情况
struct SegmentTree{
int l,r;
int maxn,minn;
}t[maxnn*]; void add(int x,int y)
{
edge[++tot].to=y;
edge[tot].next=head[x];
head[x]=tot;
} void dfs(int u,int fa)
{
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(v==fa) continue;
pre[v]=i;
dfs(v,u);
}
} void init()
{
queue<int>q;
q.push(),d[]=;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(d[v]) continue;
d[v]=d[u]+;
f[v][]=u;
for(int j=;j<=lim;j++)
f[v][j]=f[f[v][j-]][j-];
q.push(v);
}
}
} int Lca(int x,int y)
{
if(d[x]>d[y]) swap(x,y);
for(int i=lim;i>=;i--)
if(d[f[y][i]]>=d[x]) y=f[y][i];
if(x==y) return x;
for(int i=lim;i>=;i--)
if(f[y][]!=f[x][]) y=f[y][],x=f[x][];
return f[x][];
} void pre_lca()
{
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
{
if(j==i+) lca[i][j]=Lca(i,j);
else lca[i][j]=Lca(lca[i][j-],j);
}
} void work(int l,int r)
{
int fa=lca[l][r];
ll tmp=;
memset(vis,,sizeof(vis));
for(int i=l;i<=r;i++)
{
int orz=i;
while(orz!=fa)
{
if(!vis[pre[orz]]) tmp++,vis[pre[orz]]=;
orz=f[orz][];
}
}
ans+=tmp;
} void dfs_lace(int u)
{
vis[u]=;
for(int i=head[u];i;i=edge[i].next)
{
int v=edge[i].to;
if(vis[v]) continue;
d[v]=d[u]+;
dfs_lace(v);
}
} void build(int p,int l,int r)
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].maxn=d[l];
t[p].minn=d[l];
return ;
}
int mid=(l+r)>>;
build(p*,l,mid);
build(p*+,mid+,r);
t[p].maxn=max(t[p*].maxn,t[p*+].maxn);
t[p].minn=min(t[p*].minn,t[p*+].minn);
} int ask1(int p,int l,int r)
{
if(t[p].l==l&&t[p].r==r) return t[p].maxn;
int mid=(t[p].l+t[p].r)>>;
if(l>mid) return ask1(p*+,l,r);
else if(r<=mid) return ask1(p*,l,r);
else return max(ask1(p*,l,mid),ask1(p*+,mid+,r));
} int ask2(int p,int l,int r)
{
if(t[p].l==l&&t[p].r==r) return t[p].minn;
int mid=(t[p].l+t[p].r)>>;
if(l>mid) return ask2(p*+,l,r);
else if(r<=mid) return ask2(p*,l,r);
else return min(ask2(p*,l,mid),ask2(p*+,mid+,r));
} int main()
{
freopen("treecnt.in","r",stdin);
freopen("treecnt.out","w",stdout);
scanf("%d",&n);
if(n>)
{
for(int i=;i<=n-;i++)
{
int x=,y=;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
du[x]++;du[y]++;
}
for(int i=;i<=n;i++)
if(du[i]==)
{
root=i;
break;
}
d[root]=;
dfs_lace(root);
build(,,n);
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
{
int qwq=ask1(,i,j);
int orz=ask2(,i,j);
ans+=qwq-orz;
}
printf("%lld",ans);
return ;
}
lim=log2(n)+;
for(int i=;i<=n-;i++)
{
int x=,y=;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(,);
for(int i=;i<=n;i++)
pre[i]=(pre[i]+)>>;
init();
pre_lca();
// 开始乱搞n^3logn
for(int i=;i<=n;i++)
for(int j=i+;j<=n;j++)
work(i,j);
printf("%lld\n",ans);
return ;
}

考场--40pts treecnt

正解:鸽了qwq。

今天补上

期望得分:100+60+60=220

实际得分:100+30+40=170

暴力分打的比以前多了,但还是比期望少了很多,出现了很多意料外的问题...

小结:今天的题目感觉比较简单的样子,感觉暴力分好打而且分多==没想到是Day2的难度,T1就考树不资瓷,然后三道题都可能用的倍增 ,这样真的好么qwq。没有我最不擅长的dp就很资瓷,因为我连普及组的dp水平都达不到。而且出了两道树上的问题,我还是比较擅长的,很资瓷。否则我绝对拿不到人生中第一个也是最后一个rank1(大概是因为有Dalao挂题了以及今天获得了生日buff)然后吐槽一下题解,就会说暴力枚举判断,不能说详细一些嘛(逃)。

另:不会明天考dp吧qwq。

最新文章

  1. 搭建selenium grid简单配置
  2. maven出现 -Dmaven.multiModuleProjectDirectory system propery错误
  3. 点评App wiki-git标准实践
  4. 受教了,memcache比较全面点的介绍,受益匪浅,适用memcached的业务场景有哪些?memcached的cache机制是怎样的?在设计应用时,可以通过Memcached缓存那些内容?
  5. jquery 自动调整图片大小
  6. PHP上传文件超过了最大文件大小限制导致无法上传成功
  7. [APIO2015]八邻旁之桥
  8. 【翻译】使用Sencha Ext JS创建美丽的图画(1)
  9. 蚂蚁 uva 10881
  10. java基础问题巩固(1)
  11. ArcFace虹软与Dlib人脸识别对比
  12. MVC5 Entity Framework学习
  13. 命令行神器 Click 简明笔记
  14. Spring Caching集成Ehcache
  15. mysql千万级数据库插入速度和读取速度的调整记录
  16. mysql数据库导出CSV乱码问题
  17. MVC ---- DBHelper.ttinclude
  18. 理解粒子滤波(particle filter)
  19. 第二十一章 springboot + 定时任务
  20. javascript:window.history.forward(1);

热门文章

  1. Codeforces 486E LIS of Sequence(线段树+LIS)
  2. angularJS---自己定义过滤器
  3. 中科燕园GIS外包---交通运输综合地理信息平台
  4. POJ 3414:Pots
  5. 李洪强iOS开发之- 点击屏幕遮挡键盘
  6. atitit.窗口静听esc退出本窗口java swing c# .net php
  7. Redis相关知识
  8. Xammp修改端口
  9. 【 D3.js 进阶系列 — 1.2 】 读取 CSV 文件时乱码的解决方法
  10. python day- 10 动态参数 函数的嵌套 命名空间和作用域 global和nolocal