18/9/21模拟赛

期望得分:100;实际得分:0  qwq

拿到题目第一眼,我去,这不是洛谷原题(仓鼠找Sugar)吗

又多看了几眼,嗯,对,除了是有多组数据外,就是原题

然后码码码。。。。自以为写的很对 qwq

评测结束后。。。为什么我T1没有输出啊啊啊。。。

经某童鞋帮忙,发现

第一次被文件输入输出坑 qwqwq。。。

加上后就A了,白丢100 pts 蓝瘦

思路:树剖分别求LCA,然后判断LCA是否在另一条路径上

不要忘记清空数组!

#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
const int M = ;
int T, n, m, tot;
int to[M << ], net[M << ], head[M];
int deep[M], top[M], dad[M], size[M]; void add(int u, int v) {
to[++tot] = v; net[tot] = head[u]; head[u] = tot;
to[++tot] = u; net[tot] = head[v]; head[v] = tot;
} void dfs(int now) {
size[now] = ;
deep[now] = deep[dad[now]] + ;
for (int i = head[now]; i; i = net[i])
if (to[i] != dad[now]) {
dad[to[i]] = now;
dfs(to[i]);
size[now] += size[to[i]];
}
} void dfsl(int now) {
int t = ;
if (!top[now]) top[now] = now;
for (int i = head[now]; i; i = net[i])
if (to[i] != dad[now] && size[to[i]] > size[t])
t = to[i];
if (t) {
top[t] = top[now];
dfsl(t);
}
for (int i = head[now]; i; i = net[i])
if (to[i] != dad[now] && to[i] != t)
dfsl(to[i]);
} int lca(int x, int y) {
while (top[x] != top[y]) {
if (deep[top[x]] < deep[top[y]])
swap(x, y);
x = dad[top[x]];
}
return deep[x] > deep[y] ? y : x;
} void clear() {
tot = ;
memset(to, , sizeof to);
memset(net, , sizeof net);
memset(dad, , sizeof dad);
memset(top, , sizeof top);
memset(head, , sizeof head);
memset(deep, , sizeof deep);
memset(size, , sizeof size);
} int main() {
freopen("railway.in","r",stdin);
freopen("railway.out","w",stdout);
scanf("%d", &T);
for (int q = ; q <= T; ++q) {
if (q != ) clear();
scanf("%d%d", &n, &m);
for (int i = ; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
add(u, v);
}
dfs();
dfsl();
for (int i = ; i <= m; ++i) {
int a, b, c, d;
scanf("%d%d%d%d", &a, &b, &c, &d);
int S = lca(a, b);
int R = lca(c, d);
if (S < R) {
swap(S, R);
swap(a, c);
swap(b, d);
}
if (lca(S, c) == S || lca(S, d) == S) printf("YES\n");
else printf("NO\n");
}
}
fclose(stdin); fclose(stdout);
return ;
}

期望得分:100? 实际得分:20  (那80pts的都TLE了。。。)

思路:线段树维护区间的最大最小值,然后枚举每一个区间求解

事实证明,我真的不会算时间复杂度 qwq

#include <algorithm>
#include <cstring>
#include <cstdio> #ifdef WIN32
#define LL "%I64d\n"
#else
#define LL "%lld\n"
#endif using namespace std;
typedef long long Ll;
const int M = ;
int n, m;
Ll ans;
int ll[M << ], rr[M << ];
int maxn[M << ], minn[M << ]; void update(int now) {
maxn[now] = max(maxn[now << ], maxn[now << | ]);
minn[now] = min(minn[now << ], minn[now << | ]);
} void build(int now, int l, int r) {
ll[now] = l; rr[now] = r;
if (l == r) {
scanf("%d", &maxn[now]);
minn[now] = maxn[now];
return ;
}
int mid = (l + r) >> ;
build(now << , l, mid);
build(now << | , mid + , r);
update(now);
} int query(int now, int l, int r) {
if (ll[now] == l && rr[now] == r)
return maxn[now];
int mid = (ll[now] + rr[now]) >> ;
if (l <= mid && mid < r) return max(query(now << , l, mid), query(now << | , mid + , r));
else if (r <= mid) return query(now << , l, r);
else return query(now << | , l, r);
} int found(int now, int l, int r) {
if (ll[now] == l && rr[now] == r)
return minn[now];
int mid = (ll[now] + rr[now]) >> ;
if (l <= mid && mid < r) return min(found(now << , l, mid), found(now << | , mid + , r));
else if (r <= mid) return found(now << , l, r);
else return found(now << | , l, r);
} void clear() {
ans = ;
memset(ll, , sizeof ll);
memset(rr, , sizeof rr);
memset(maxn, , sizeof maxn);
memset(minn, , sizeof minn);
} int main() {
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
scanf("%d", &m);
for (int q = ; q <= m; ++q) {
if (q != ) clear();
scanf("%d", &n);
build(, , n);
for (int i = ; i <= n; ++i)
for (int j = i + ; j <= n; ++j)
ans += (query(, i, j) - found(, i, j));
printf(LL, ans);
}
fclose(stdin); fclose(stdout);
return ;
}

考场20pts代码

正解:因为排列是随机的,所以从每个点向后可能的差值最多 2logn 个,所以答案最多只可能有nlogn 种,用单调队列找出来统计即可

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
#define putk() putchar(' ')
ld eps=1e-;
ll pp=;
ll mo(ll a,ll pp){if(a>= && a<pp)return a;a%=pp;if(a<)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=;for(;b;b>>=,a=mo(a*a,pp))if(b&)ans=mo(ans*a,pp);return ans;}
ll gcd(ll a,ll b){return (!b)?a:gcd(b,a%b);}
ll read(){
ll ans=;
char last=' ',ch=getchar();
while(ch<'' || ch>'')last=ch,ch=getchar();
while(ch>='' && ch<='')ans=ans*+ch-'',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}
void put(ll a){
if(a<)putchar('-'),a=-a;
int top=,q[];
while(a)q[++top]=a%,a/=;
top=max(top,);
while(top--)putchar(''+q[top+]);
}
//head
#define N 210000
int n,a[N],f1[N],f2[N],q[N];
ll s[N];
void solved(){
n=read();
rep(i,,n)a[i]=read();
a[n+]=n+;
q[]=n+;
int t=;
per(i,n,){
while(t && a[q[t]]<=a[i])--t;
f1[i]=q[t];
q[++t]=i;
}
a[n+]=;
q[]=n+;
t=;
per(i,n,){
while(t && a[q[t]]>=a[i])--t;
f2[i]=q[t];
q[++t]=i;
}
rep(i,,n)s[i]=;
rep(i,,n){
int z1=i,z2=i;
while(z1!=n+ && z2!=n+){
if(f1[z1]<=f2[z2]){
int tt=max(z1,z2),zz=a[z1]-a[z2];
z1=f1[z1];
s[zz]+=max(z1,z2)-tt;
}
else{
int tt=max(z1,z2),zz=a[z1]-a[z2];
z2=f2[z2];
s[zz]+=max(z1,z2)-tt;
}
}
}
ll ans=;
rep(i,,n-)
ans+=s[i]*i;
cout<<ans<<endl;
}
int main(){
freopen("count.in","r",stdin);
freopen("count.out","w",stdout);
int T=read();
while(T--){
solved();
}
return ;
}

正解

比题解更好的做法  ——By lgj

分别求所有区间的最大值和、最小值和

用单调栈维护,用sum记录已经求过的区间的最大值的和

求最小值时,可将所有的数转为负数,重新跑一遍即可

最后将两次求出的值相加即可

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<iostream>
#define LL long long
using namespace std;
const LL MAXN = 1e5 + ;
inline LL read() {
char c = getchar(); LL x = , f = ;
while(c < '' || c > '') {if(c == '-') f = -; c = getchar();}
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * f;
}
LL T, N;
LL a[MAXN], q[MAXN];
LL solve() {
LL h = , t = , ans = , sum = ;
for(LL i = ; i <= N; i++) {
while(h <= t && a[i] > a[q[t]]) sum -= a[q[t]] * (q[t] - q[t - ]), t--;
q[++t] = i;
ans += a[i] * (q[t] - q[t - ]) + sum;
sum += a[i] * (q[t] - q[t - ]);
}
return ans;
}
int main() {
freopen("count.in", "r", stdin);
freopen("count.out", "w", stdout);
T = read();
while(T--) {
N = read();
for(LL i = ; i <= N; i++) a[i] = read();
LL ans = solve();
for(LL i = ; i <= N; i++) a[i] = -a[i];
LL ans2 = solve();
cout << ans + ans2 << endl;
}
return ;
}

% lgj dalao

期望得分:0;实际得分:0

一开始以为样例错了,死活推不出来

前一个小时做了前两题,剩下的时间大部分就在推样例发呆中度过了

最后半小时才发现读错题 qwq

然而暴力也写不完了。。。

正解:对于每一条边统计有多少个区间跨过这条边即可

统计这一问题的对偶问题,有多少个区间没跨过会更方便

使用启发式合并+并查集统计子树内的,使用启发式合并+set 统计子树外的

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pr;
const double pi=acos(-);
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define Rep(i,u) for(int i=head[u];i;i=Next[i])
#define clr(a) memset(a,0,sizeof a)
#define pb push_back
#define mp make_pair
ld eps=1e-;
ll pp=;
ll mo(ll a,ll pp){if(a>= && a<pp)return a;a%=pp;if(a<)a+=pp;return a;}
ll powmod(ll a,ll b,ll pp){ll ans=;for(;b;b>>=,a=mo(a*a,pp))if(b&)ans=mo(ans*a,pp);return ans;}
ll read(){
ll ans=;
char last=' ',ch=getchar();
while(ch<'' || ch>'')last=ch,ch=getchar();
while(ch>='' && ch<='')ans=ans*+ch-'',ch=getchar();
if(last=='-')ans=-ans;
return ans;
}
//head
#define N 110000
int head[N],Next[N*],v[N*],num,fa[N],son[N],sum[N],n,s[N],Fa[N];
ll ans=,Sum,Sum2;
bool vis[N];
set<int>Q;
set<int>::iterator it,it1,it2;
int find(int x){
if(x==Fa[x])return x;
return Fa[x]=find(Fa[x]);
}
void add(int x,int y){
v[++num]=y;Next[num]=head[x];head[x]=num;
}
void dfs1(int u){
sum[u]=;son[u]=;
for(int i=head[u];i;i=Next[i])
if(v[i]!=fa[u]){
fa[v[i]]=u;
dfs1(v[i]);
sum[u]+=sum[v[i]];
if(!son[u] || sum[v[i]]>sum[son[u]])son[u]=v[i];
}
}
ll cal(ll n){
return n*(n-)/;
}
void Add(int u){
Q.insert(u);
it=Q.find(u);
it1=it2=it;
it1--;it2++;
Sum2-=cal((*it2)-(*it1)-);
Sum2+=cal((*it)-(*it1)-)+cal((*it2)-(*it)-);
vis[u]=;
if(vis[u-]){
int fx=find(u-),fy=find(u);
Sum+=(ll)s[fx]*s[fy];
Fa[fx]=fy;
s[fy]+=s[fx];
}
if(vis[u+]){
int fx=find(u+),fy=find(u);
Sum+=(ll)s[fx]*s[fy];
Fa[fx]=fy;
s[fy]+=s[fx];
}
}
void bfs(int u){
Add(u);
for(int i=head[u];i;i=Next[i])
if(v[i]!=fa[u])bfs(v[i]);
}
void clear(int u){
s[u]=;vis[u]=;Fa[u]=u;
for(int i=head[u];i;i=Next[i])
if(v[i]!=fa[u])clear(v[i]);
}
void dfs2(int u){
for(int i=head[u];i;i=Next[i])
if(v[i]!=fa[u] && v[i]!=son[u]){
dfs2(v[i]);
clear(v[i]);
Sum=;
Q.clear();
Q.insert();
Q.insert(n+);
Sum2=(ll)(n-)*n/;
} if(son[u])dfs2(son[u]);
for(int i=head[u];i;i=Next[i])
if(v[i]!=fa[u] && v[i]!=son[u])bfs(v[i]); Add(u); ans+=(ll)n*(n-)/-Sum-Sum2;
}
int main(){
freopen("treecnt.in","r",stdin);
freopen("treecnt.out","w",stdout);
n=read();
Q.clear();
Q.insert();
Q.insert(n+);
Sum2=cal(n);
rep(i,,n)Fa[i]=i,s[i]=,vis[i]=;
rep(i,,n){
int x=read(),y=read();
add(x,y);
add(y,x);
}
dfs1();
dfs2();
cout<<ans<<endl;
return ;
}

正解

18/9/21模拟赛-Updated的更多相关文章

  1. 【2018.10.18】noip模拟赛Day2 地球危机(2018年第九届蓝桥杯C/C++A组省赛 三体攻击)

    题目描述 三体人将对地球发起攻击.为了抵御攻击,地球人派出了 $A × B × C$ 艘战舰,在太 空中排成一个 $A$ 层 $B$ 行 $C$ 列的立方体.其中,第 $i$ 层第 $j$ 行第 $k ...

  2. 18.09.22模拟赛T2 历史

    网上基本上找不到这道题,何况LJJ还稍微改了一下...... 原题:传送门 题目描述 ljj 被S 国数不清的漂亮小姐姐所吸引,为了搞清楚为什么S 国有如此多的漂亮小姐姐,他决定研究S 国的历史. 根 ...

  3. 6.18 省选模拟赛 树 倍增 LCT

    LINK:树 考虑暴力 保存每个版本的父亲 然后暴力向上跳.得分20. 考虑离线 可以离线那么就可以先把树给搞出来 然后考虑求k级祖先 可以倍增求. 如何判断合法 其实要求路径上的边的时间戳<= ...

  4. 6.18 省选模拟赛 字符串 LCT SAM

    LINK:字符串 看起来很难做 考虑一种暴力 建立SAM后每次查询暴力扫儿子. 期望得分10分.实际得分10分. 另外一种发现每次扫儿子过于暴力 可以每次儿子向上做贡献 每次都暴力向上跳. 期望得分1 ...

  5. 4.18 省选模拟赛 无聊的计算器 CRT EXBSGS EXLucas

    算是一道很毒瘤的题目 考试的时候码+调了3h才搞定. op==1 显然是快速幂. op==2 有些点可以使用BSGS 不过后面的点是EXBSGS. 这个以前学过了 考试的时候还是懵逼.(当时还是看着花 ...

  6. [10.18模拟赛] 序列 (DP)

    [10.18模拟赛] 序列 题目描述 山山有一个整数序列s1,s2,-,sn,其中1≤si≤k. 求出有多少个准确移除m个元素后不同的序列.答案模(1e9+7) 输入 输入包括几个测试用例,并且由文件 ...

  7. [GRYZ]寒假模拟赛

    写在前面 这是首次广饶一中的OIERS自编自导,自出自做(zuo)的模拟赛. 鉴于水平气压比较低,机(wei)智(suo)的WMY/XYD/HYXZC就上网FQ下海找了不少水(fei)题,经过他们优( ...

  8. CH Round #48 - Streaming #3 (NOIP模拟赛Day1)

    A.数三角形 题目:http://www.contesthunter.org/contest/CH%20Round%20%2348%20-%20Streaming%20%233%20(NOIP模拟赛D ...

  9. 7.29NOIP模拟赛

    7.29NOIP模拟赛 T1 YSG (1s,64MB,ysg.in,ysg.out) 描述 ysg,yxy,azw 三人正在刷题. 他们每做一题的时间都是一个有理数. 如果在某一时刻,三人同时做完一 ...

随机推荐

  1. 前端之CSS属性相关

    宽和高 width属性可以为元素设置宽度. height属性可以为元素设置高度. 块级标签才能设置宽度,内联标签的宽度由内容来决定. 字体属性 文字字体 font-family可以把多个字体名称作为一 ...

  2. WebService通讯技术的CXF框架问题

    WebService通讯技术的CXF框架问题 严重: Servlet /cxf_rs_spring threw load() exception java.lang.ClassCastExceptio ...

  3. 【转】CentOS下firefox安装flash说明

    http://www.cnblogs.com/lamper/archive/2013/01/16/2862254.htm CentOS下自带了firefox,但没有flash插件的,按它自己的提示安装 ...

  4. Java定时器TimeTask

    package com.alan.timer; import java.util.Calendar;import java.util.Date;import java.util.Timer;impor ...

  5. xml Data Type Methods in sql server

    nodes() Method (xml Data Type) https://docs.microsoft.com/en-us/sql/t-sql/xml/nodes-method-xml-data- ...

  6. org.xml.sax.SAXParseException: Content is not allowed in prolog

    sax错误:org.xml.sax.SAXParseException: Content is not allowed in prolog解决  标签: org. xml. sax. saxparse ...

  7. Linux常用视频播放器

    1.SMplayer是一款跨平台的视频播放工具,可以支持大部分的视频和音频文件.它支持音频轨道切换.允许调节亮度.对比度.色调.饱和度.伽玛值,按照倍速.4倍速等多种速度回放.还可以进行音频和字幕延迟 ...

  8. Linux常用PDF阅读软件

    1.福昕阅读器是一款PDF文档阅读器,对中文的支持度非常高.福昕阅读器作为全球最流行的PDF阅读器,能够快速打开.浏览.审阅.注释.签署及打印任何PDF文件. 2.evince是一个支持多种格式的文件 ...

  9. Codeforces Round #240 (Div. 2) 题解

    A: 1分钟题,往后扫一遍 int a[MAXN]; int vis[MAXN]; int main(){ int n,m; cin>>n>>m; MEM(vis,); ; i ...

  10. phantomjs 设置代理

    phantomjs 可通过以下设置代理ip #coding=utf-8import osimport reimport timeimport requestsfrom scrapy.selector ...