题目链接:http://acm.uestc.edu.cn/#/contest/show/155

这个数据结构训练主要针对线段树,树转数组和并查集。比较适合刚入门数据结构的同学。

注意,因为后面题的代码太长了,200+行起步,所以我只贴一些主要代码(有些题没有代码,我之后会补上)

还未更新完,正在更新中

A - An easy problem A

思路:正如其名,是道大水题。裸的RMQ,数据范围略小,也不需要单点更新,所以有很多姿势能水过去

我随便搓颗线段树就A了,时间复杂度O(Q*log(N))。

代码:这题这么简单,应该不需要代码吧,除非你没学过线段树..........

 B - An easy problem B

思路:这题题目虽然叫简单题,可是写起来好复杂ORZ。线段树+懒惰标记,时间复杂度O(m*log(n)),在结点上要维护6个域:

1.区间内的最长的1串的长度                            2.区间内的最长的0串的长度

3.区间内以区间左端点开始的最长1串的长度        3.区间内以区间左端点开始的最长0串的长度

5.区间内以区间右端点开始的最长1串的长度        6.区间内以区间右端点开始的最长0串的长度

对于上面6个域,我们分别用

这六个变量记录。

合并区间a,b时(a与b相邻且a在b的左边)时:

len1 ------ 新区间内的最长的1串的长度的来源只有3个,①a.len1 ②b.len1 ③a.r1+b.l1

说白了就是在合并地方可能会产生更长的1串,代码如下

      ans.len1=max(a.r1+b.l1,max(a.len1,b.len1));

l1 --------区间内以区间左端点开始的最长1串的长度来源只有2个  ,①a.l1 ②当a.l1=区间长度时,a.l1+b.l1

也就是说,只要特判一下,当a区间全为1情况就行了,代码如下

ans.l1=a.l1;

       if(a.l1==a.len)

       ans.l1+=b.l1;

r1 --------同理,区间内以区间右端点开始的最长1串的长度来源只有2个  ,①b.r1 ②当br1=区间长度时,b.r1+a.r1

也就是说,只要特判一下,当b区间全为1情况就行了,代码如下

      ans.r1=b.r1;

       if(a.r1==b.len)

       ans.r1+=a.r1;

0串的情况和以上完全类似,我就不写了

总的代码如下:

 void meg(Node &ans,Node &a,Node &b)
{
ans.len1=max(a.r1+b.l1,max(a.len1,b.len1));
ans.len0=max(a.r0+b.l0,max(a.len0,b.len0));
ans.l0=a.l0;
ans.l1=a.l1;
ans.r0=b.r0;
ans.r1=b.r1; if(a.l0==a.len)
{
ans.l0+=b.l0;
}
if(a.l1==a.len)
{
ans.l1+=b.l1;
}
if(b.r0==b.len)
{
ans.r0+=a.r0;
}
if(b.r1==b.len)
{
ans.r1+=a.r1;
}
ans.len=a.len+b.len;
}

接着就是懒惰标记的问题了:

显然,一个区间如果被异或两次的话,等于没被异或过。

所以累加标记时只 要 .lazy^=1;就行了

而使用标记更新当前结点时,只要交换0,1串的所有域就行了

     void fun()
{
swap(len0,len1);
swap(l0,l1);
swap(r0,r1);
}

最后就是查询了,为了减低代码复杂度,我们直接调用合并函数合并所有区间,并用些变量存下合并结结果,最后return ans.len1即可

 int query(int l,int r)
{ l+=size;
r+=size;
putdown((l)>>1,(r)>>1);
updata(l);
updata(l^1);
updata(r);
updata(r^1);
Node ans,lans,rans,temp;
if(l==r)
ans=node[l];
else
{
lans=node[l];
rans=node[r]; for(; r^l^1; l>>=1,r>>=1 )
{ updata(l);
updata(l^1);
updata(r);
updata(r^1);
if(~l&1)
{ temp=lans;
meg(lans,temp,node[l^1]); }
if(r&1)
{ temp=rans;
meg(rans,node[r^1],temp); }
}
meg(ans,lans,rans);
updata(l);
updata(r);
}
while(l>1)
{
l>>=1;
updata(l);
updata(l^1);
}
return ans.len1;
}

 C - An easy problem C

思路:比起B题,C题就简单多了,主要是考查懒惰标记,时间复杂度O(m*log(n))

难点在与标记的设置和复合

我们在标记上存两个域,一个a,一个b。代表对区间内的每个数x,进行ax+b的操作,用矩阵表示就是

1.当子区间复合一个来自父区间的标记a1,b2时,子区间的a,b的更新操作如下

void change(long long a1,long long b1)

{

  a=a1*a%p;

  b=(a1*b+b1)%p;

}

矩阵的表示如下

2.操作1,和操作2都可以看做在区间上复合上一个新标记即可

加法: node[].change(1,C);

乘法: node[].change(C,0);

3.使用标记

我们在区间存下一个域sum,代表区间和。

因为是对区间内的每个数进行a*x+b的操作,所以

所以 sum=(a*sum+b*len)%p;

4.接着就是合并区间的操作了

这没啥好说的,就是sum=a.sum+b.sum

5.这里要注意一下,标记为空时,应该是a=1,b=0

因为x=1*x+0;所以初始化时,和清除标记时都应该是执行下面这个操作

void clc()

{   

  a=1;

  b=0;

}

 D - Washi与Sonochi的约定

思路:这题比较简单主要是考查点转化模型的脑洞,我门先将所有点按x坐标从小到大排好序,然后问题就变成,在一个位置前面有多少个点的y坐标比他小,

这就变成了经典的求顺/逆序数的问题了。时间复杂度O(n*log(n))

代码:求逆序数的代码可以看下一题

 E - 曜酱的心意

思路:这题也是脑洞题,我们先求一个映射F(x),把a1,a2,a3……an映射成1,2,3,……n,再对bn使用一下这个映射。

这时an变成的从小到大的有序数列。则求bn变成an的最小交换次数就等价于求用冒泡排序对bn排序至少要用多少次交换。

答案是bn的所有数的逆序数之和。所以同上题时间复杂度O(n*log(n))

代码

#include<stdio.h>
#include<string.h>
int a[100005],b[100005],f[100005];
int c[100010],n;
inline int Lowbit(int x)
{
return x&(-x);
}
int getsum(int ed)
{
int sum=0;
while(ed>0)
{
sum+=c[ed];
ed-=Lowbit(ed);
}
return sum;
}
void update(int pos,int num)
{
while(pos<=n)
{
c[pos]+=num;
pos+=Lowbit(pos);
}
}
int main()
{
int i,j,top=0,m,fp,flag,k,x;
long long sum;
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&a[i]);
f[a[i]]=i;
}
for(i=1;i<=n;i++)
{
scanf("%d",&b[i]);
b[i]=f[b[i]];
}
sum=0;
for(i=n;i>=1;i--)
{
sum+=getsum(b[i]);///求1到b[i]中有多少个数
update(b[i],1);///把b[i]位置更新为1.代表这个位置上有一个数
}
printf("%lld\n",sum);
return 0;
}

 F - 奇迹的魔法啊,再度出现!

思路:经典的01字典树的题目,时间复杂O(31*(N+M)).

预处理:我们先把所有的ai拆分成31长度的二进制串,并按照从高位到低位的顺序全部插入到颗二叉字典树中。

查询:也把每个要查询的bi拆分成31长度的二进制,然后在字典树上从高位到低位贪心查询即可

代码如下:

#include<stdio.h>
#include<math.h>
#include<set>
using namespace std;
struct tree
{
tree * next[2];
tree()
{
next[0]=next[1]=NULL;
}
}head;
void insert(int bit[])
{
int i;
tree *p=&head;
for(i=30;i>=0;i--)
{
if(p->next[bit[i]]==NULL)
{
p->next[bit[i]]=new tree();
}
p=p->next[bit[i]];
}
}
int find(int bit[])
{
int i,sum=0;
tree *p=&head;
for(i=30;i>=0;i--)
{
sum<<=1;
if(p->next[bit[i]^1]==NULL)
{
p=p->next[bit[i]];
}
else
{
sum++;
p=p->next[bit[i]^1];
}
}
return sum;
}
int a[40];
void bin(int n)
{
int i;
for(i=0;i<31;i++,n>>=1)
a[i]=n&1;
}
int main()
{
int t,n,m,i,l,r,x,s1,s2,j,flag;
scanf("%d",&n);
while(n--)
{
scanf("%d",&x);
bin(x);
insert(a);
}
scanf("%d",&m);
while(m--)
{
scanf("%d",&x);
bin(x);
printf("%d\n",find(a));
}
return 0;
}

 G - 加帕里公园的friends

思路:线段树,所以复杂度时间复杂度(m*log(n)*log(n))

2017 UESTC Training for Data Structures-解题报告的更多相关文章

  1. 2017 UESTC Training for Data Structures

    http://acm.uestc.edu.cn/#/contest/show/155 对大二来说貌似这套题有点简单了,多是一眼题 发现漏了一题,然而是以前看别人讨论过的:). H:线段树+暴力.大概就 ...

  2. UESTC_Rain in ACStar 2015 UESTC Training for Data Structures<Problem L>

    L - Rain in ACStar Time Limit: 9000/3000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Other ...

  3. UESTC_Sliding Window 2015 UESTC Training for Data Structures<Problem K>

    K - Sliding Window Time Limit: 18000/6000MS (Java/Others)     Memory Limit: 131072/131072KB (Java/Ot ...

  4. UESTC_Islands 2015 UESTC Training for Data Structures<Problem J>

    J - Islands Time Limit: 30000/10000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Su ...

  5. UESTC_秋实大哥与战争 2015 UESTC Training for Data Structures<Problem D>

    D - 秋实大哥与战争 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Subm ...

  6. UESTC_秋实大哥与快餐店 2015 UESTC Training for Data Structures<Problem C>

    C - 秋实大哥与快餐店 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Sub ...

  7. UESTC_秋实大哥搞算数 2015 UESTC Training for Data Structures<Problem N>

    N - 秋实大哥搞算数 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Subm ...

  8. UESTC_秋实大哥与线段树 2015 UESTC Training for Data Structures<Problem M>

    M - 秋实大哥与线段树 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Sub ...

  9. UESTC_秋实大哥下棋 2015 UESTC Training for Data Structures<Problem I>

    I - 秋实大哥下棋 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submi ...

随机推荐

  1. NOIP模拟赛 混合图

    [题目描述] Hzwer神犇最近又征服了一个国家,然后接下来却也遇见了一个难题. Hzwer的国家有n个点,m条边,而作为国王,他十分喜欢游览自己的国家.他一般会从任意一个点出发,随便找边走,沿途欣赏 ...

  2. [BZOJ] 1520: [POI2006]Szk-Schools

    费用流解决. abs内传不了int..CE一次 #include<iostream> #include<cstring> #include<cstdio> #inc ...

  3. 转 Spring Security 简介

    https://blog.csdn.net/xlecho/article/details/80026527 Spring Security 简介 2018年04月21日 09:53:02 阅读数:13 ...

  4. tomcat关闭钩子

    转 http://501565246-qq-com.iteye.com/blog/1733575 21,tomcat关闭钩子 博客分类: tomcat   在很多环境下,在关闭应用程序的时候需要做一些 ...

  5. release判断系统

    #!/bin/bash # Name: Atomic Archive configuration script # Copyright Atomicorp, 2002-2018 # License: ...

  6. 再生龙备份还原linux系统

    相关下载: Clonezilla再生龙:http://sourceforge.net/projects/clonezilla/files/clonezilla_live_stable/ tuxboot ...

  7. python入门:最基本的用户登录

    #! usr/bin/env python # -*- coding: utf-8 -*- #最基本的用户登录 import getpass usre = input("username:& ...

  8. java代码导出数据到Excel、js导出数据到Excel(三)

     jsp内容忽略,仅写个出发按钮:          <button style="width: 100px" onclick="expertExcel()&quo ...

  9. 《linux设备驱动开发详解》笔记——10中断与时钟

    10.1 中断与定时器 中断一般有如下类型: 内部中断和外部中断:内部中断来自CPU,例如软件中断指令.溢出.除0错误等:外部中断有外部设备触发 可屏蔽中断和不可屏蔽中断 向量中断和非向量中断,ARM ...

  10. Python中的列表(1)

    1.什么是列表? 列表是由一组按特定顺序排列的元素组成. 2.如何表示? 在Python中用方括号([ ])来表示列表.栗子如下: contries = ['China','England','Fra ...